SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)
恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。 == 此快照内容 == - 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091) - 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static) - 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB) - 交接文档 go.md + go-code-reference/endpoints/entities/database.md - 多代理建设脚本 .claude/wf-*.js == 状态 == - 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板) - 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用 - W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成) - 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456 == 排除(gitignore, 可再生) == node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui) 完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules) 时间戳: 20260615-191517 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
package com.kaidi.oa.seed;
|
||||
|
||||
import com.kaidi.oa.common.Money;
|
||||
import com.kaidi.oa.domain.FinAccountAux;
|
||||
import com.kaidi.oa.domain.FinBudgetExecution;
|
||||
import com.kaidi.oa.domain.FinBudgetPlan;
|
||||
import com.kaidi.oa.domain.FinCostCalc;
|
||||
import com.kaidi.oa.domain.FinVoucherTemplate;
|
||||
import com.kaidi.oa.repository.FinAccountAuxRepository;
|
||||
import com.kaidi.oa.repository.FinBudgetExecutionRepository;
|
||||
import com.kaidi.oa.repository.FinBudgetPlanRepository;
|
||||
import com.kaidi.oa.repository.FinCostCalcRepository;
|
||||
import com.kaidi.oa.repository.FinVoucherTemplateRepository;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
/**
|
||||
* 财务部演示种子数据(缺口 #1/#8/#11 — 活体 0 条)。
|
||||
*
|
||||
* 补齐:
|
||||
* - FinAccountAux(辅助核算配置,缺口#1):6 条跨维度配置 + 余额
|
||||
* - FinVoucherTemplate(凭证模板,缺口#1):7 条常用模板(各类型各一条)
|
||||
* - FinCostCalc(成本核算记录,缺口#8):6 条跨方法/状态核算记录
|
||||
* - FinBudgetPlan(预算编制计划,缺口#11):5 条跨部门/类型预算申报
|
||||
* - FinBudgetExecution(预算执行,缺口#11):5 条已批准后生成的执行记录
|
||||
*
|
||||
* 幂等:各表 count > 0 即跳过。
|
||||
*
|
||||
* @Order(12) 在 DataSeeder(@Order 1) 之后运行。
|
||||
*/
|
||||
@Component
|
||||
@Order(12)
|
||||
public class FinDeptSeeder implements ApplicationRunner {
|
||||
|
||||
private final FinAccountAuxRepository auxRepo;
|
||||
private final FinVoucherTemplateRepository templateRepo;
|
||||
private final FinCostCalcRepository costCalcRepo;
|
||||
private final FinBudgetPlanRepository budgetPlanRepo;
|
||||
private final FinBudgetExecutionRepository budgetExecRepo;
|
||||
|
||||
public FinDeptSeeder(FinAccountAuxRepository auxRepo,
|
||||
FinVoucherTemplateRepository templateRepo,
|
||||
FinCostCalcRepository costCalcRepo,
|
||||
FinBudgetPlanRepository budgetPlanRepo,
|
||||
FinBudgetExecutionRepository budgetExecRepo) {
|
||||
this.auxRepo = auxRepo;
|
||||
this.templateRepo = templateRepo;
|
||||
this.costCalcRepo = costCalcRepo;
|
||||
this.budgetPlanRepo = budgetPlanRepo;
|
||||
this.budgetExecRepo = budgetExecRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void run(ApplicationArguments args) {
|
||||
seedAccountAux();
|
||||
seedVoucherTemplates();
|
||||
seedCostCalc();
|
||||
seedBudgetPlan();
|
||||
seedBudgetExecution();
|
||||
}
|
||||
|
||||
// ===================== 辅助核算配置 =====================
|
||||
private void seedAccountAux() {
|
||||
if (auxRepo.count() > 0) return;
|
||||
|
||||
Object[][] data = {
|
||||
{ "1122", "应收账款", "客户", "凯迪新能源科技有限公司", "2026-01", new BigDecimal("856300.00") },
|
||||
{ "1122", "应收账款", "客户", "汉阳市政建设集团", "2026-01", new BigDecimal("432100.00") },
|
||||
{ "6602", "管理费用", "部门", "研发部", "2026-01", new BigDecimal("123450.00") },
|
||||
{ "6602", "管理费用", "部门", "生产部", "2026-01", new BigDecimal("98760.00") },
|
||||
{ "6401", "主营业务成本", "项目", "KD-2025-001 污水处理一期", "2026-01", new BigDecimal("2156800.00") },
|
||||
{ "6401", "主营业务成本", "成本中心", "车间A-焊接工段", "2026-01", new BigDecimal("78900.00") },
|
||||
};
|
||||
|
||||
for (Object[] row : data) {
|
||||
FinAccountAux a = new FinAccountAux();
|
||||
a.setAccountCode((String) row[0]);
|
||||
a.setAccountName((String) row[1]);
|
||||
a.setAuxDimension((String) row[2]);
|
||||
a.setAuxVal((String) row[3]);
|
||||
a.setEnabledVal(FinAccountAux.STATUS_ENABLED);
|
||||
a.setBalance((BigDecimal) row[5]);
|
||||
a.setApplicant("admin");
|
||||
a.setReason("初始化辅助核算配置");
|
||||
a.setCreatedAt(Instant.now().minus(30, ChronoUnit.DAYS));
|
||||
a.setUpdatedAt(Instant.now().minus(1, ChronoUnit.DAYS));
|
||||
auxRepo.save(a);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 凭证模板 =====================
|
||||
private void seedVoucherTemplates() {
|
||||
if (templateRepo.count() > 0) return;
|
||||
|
||||
Object[][] data = {
|
||||
{ "TMPL-001", "月度折旧计提", FinVoucherTemplate.TYPE_DEPREC, "6602", "1602", "计提${period}固定资产折旧", "折旧计算" },
|
||||
{ "TMPL-002", "无形资产摊销", FinVoucherTemplate.TYPE_AMORT, "6602", "1702", "摊销${period}无形资产", "摊销计算" },
|
||||
{ "TMPL-003", "月末结转损益", FinVoucherTemplate.TYPE_TRANSFER, "6001", "4103", "${period}结转主营业务收入至本年利润", "手填" },
|
||||
{ "TMPL-004", "结转研发费用", FinVoucherTemplate.TYPE_RD, "6602", "5301", "${period}研发费用化支出结转管理费", "手填" },
|
||||
{ "TMPL-005", "制造费用按工时分摊", FinVoucherTemplate.TYPE_MFG, "1321", "6601", "${period}制造费用分摊至在制品", "手填" },
|
||||
{ "TMPL-006", "期末汇率折算调整", FinVoucherTemplate.TYPE_FX, "6601", "2202", "${period}外币汇兑损益调整", "手填" },
|
||||
{ "TMPL-007", "备用金借款发放", FinVoucherTemplate.TYPE_MANUAL, "1001", "1002", "发放${period}员工备用金借款", "手填" },
|
||||
};
|
||||
|
||||
for (Object[] row : data) {
|
||||
FinVoucherTemplate t = new FinVoucherTemplate();
|
||||
t.setCode((String) row[0]);
|
||||
t.setName((String) row[1]);
|
||||
t.setTemplateType((String) row[2]);
|
||||
t.setDebitAccount((String) row[3]);
|
||||
t.setCreditAccount((String) row[4]);
|
||||
t.setSummaryTemplate((String) row[5]);
|
||||
t.setAmountSource((String) row[6]);
|
||||
t.setEnabled(Boolean.TRUE);
|
||||
t.setCreatedBy("admin");
|
||||
t.setCreatedAt(Instant.now().minus(60, ChronoUnit.DAYS));
|
||||
templateRepo.save(t);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 成本核算记录 =====================
|
||||
private void seedCostCalc() {
|
||||
if (costCalcRepo.count() > 0) return;
|
||||
|
||||
Object[][] data = {
|
||||
// code, method, object, objType, period, dm, dl, mo, driver, drvQty, rate, std, status
|
||||
{ "CC-2026-001", FinCostCalc.METHOD_VARIETY, "KD-A01 污水处理设备", "产品", "2026-01",
|
||||
new BigDecimal("158000.00"), new BigDecimal("43200.00"), new BigDecimal("22800.00"),
|
||||
"工时", 480.0, new BigDecimal("47.50"), new BigDecimal("210000.00"), FinCostCalc.STATUS_POSTED },
|
||||
{ "CC-2026-002", FinCostCalc.METHOD_BATCH, "KD-WO-2026-003 生产批次", "工单", "2026-01",
|
||||
new BigDecimal("89600.00"), new BigDecimal("18900.00"), new BigDecimal("11200.00"),
|
||||
"产量", 120.0, new BigDecimal("93.33"), new BigDecimal("115000.00"), FinCostCalc.STATUS_APPROVED },
|
||||
{ "CC-2026-003", FinCostCalc.METHOD_PROCESS, "污水处理剂-第一步骤", "产品", "2026-01",
|
||||
new BigDecimal("62300.00"), new BigDecimal("12100.00"), new BigDecimal("8600.00"),
|
||||
"工时", 200.0, new BigDecimal("43.00"), new BigDecimal("80000.00"), FinCostCalc.STATUS_APPROVED },
|
||||
{ "CC-2026-004", FinCostCalc.METHOD_ABC, "KD-PRJ-2025-012 污水项目", "项目", "2026-01",
|
||||
new BigDecimal("310500.00"), new BigDecimal("87600.00"), new BigDecimal("48300.00"),
|
||||
"工时", 960.0, new BigDecimal("50.31"), new BigDecimal("430000.00"), FinCostCalc.STATUS_POSTED },
|
||||
{ "CC-2026-005", FinCostCalc.METHOD_VARIETY, "KD-B02 曝气设备", "产品", "2025-12",
|
||||
new BigDecimal("241000.00"), new BigDecimal("55000.00"), new BigDecimal("31000.00"),
|
||||
"产量", 60.0, new BigDecimal("516.67"), new BigDecimal("320000.00"), FinCostCalc.STATUS_POSTED },
|
||||
{ "CC-2026-006", FinCostCalc.METHOD_BATCH, "KD-ORD-2026-008 订单成本","订单","2026-02",
|
||||
new BigDecimal("124800.00"), new BigDecimal("32000.00"), new BigDecimal("19200.00"),
|
||||
"收入", 0.0, new BigDecimal("0.00"), new BigDecimal("170000.00"), FinCostCalc.STATUS_DRAFT },
|
||||
};
|
||||
|
||||
for (Object[] row : data) {
|
||||
FinCostCalc c = new FinCostCalc();
|
||||
c.setCode((String) row[0]);
|
||||
c.setCalcMethod((String) row[1]);
|
||||
c.setCostObject((String) row[2]);
|
||||
c.setCostObjectType((String) row[3]);
|
||||
c.setPeriod((String) row[4]);
|
||||
c.setDirectMaterial((BigDecimal) row[5]);
|
||||
c.setDirectLabor((BigDecimal) row[6]);
|
||||
c.setManufacturingOverhead((BigDecimal) row[7]);
|
||||
c.setAllocationDriver((String) row[8]);
|
||||
c.setDriverQuantity((Double) row[9]);
|
||||
c.setAllocationRate((BigDecimal) row[10]);
|
||||
BigDecimal total = ((BigDecimal) row[5]).add((BigDecimal) row[6]).add((BigDecimal) row[7]);
|
||||
c.setTotalCost(total);
|
||||
c.setStandardCost((BigDecimal) row[11]);
|
||||
c.setCostVariance(total.subtract((BigDecimal) row[11]));
|
||||
c.setStatus((String) row[12]);
|
||||
c.setOperator("admin");
|
||||
c.setCreatedAt(Instant.now().minus(20, ChronoUnit.DAYS));
|
||||
costCalcRepo.save(c);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 预算编制计划 =====================
|
||||
private void seedBudgetPlan() {
|
||||
if (budgetPlanRepo.count() > 0) return;
|
||||
|
||||
Object[][] data = {
|
||||
{ "BP-2026-001", "2026", 1, "研发部", "费用预算", "研发人员人工费用", new BigDecimal("2400000.00"), new BigDecimal("2200000.00"), FinBudgetPlan.S_APPROVED },
|
||||
{ "BP-2026-002", "2026", 1, "生产部", "成本预算", "直接材料采购成本", new BigDecimal("8600000.00"), new BigDecimal("8100000.00"), FinBudgetPlan.S_APPROVED },
|
||||
{ "BP-2026-003", "2026", 1, "行政部", "费用预算", "办公及行政费用", new BigDecimal("380000.00"), new BigDecimal("360000.00"), FinBudgetPlan.S_APPROVED },
|
||||
{ "BP-2026-004", "2026", 1, "销售部", "收入预算", "主营业务收入", new BigDecimal("42000000.00"),new BigDecimal("40000000.00"),FinBudgetPlan.S_APPROVED },
|
||||
{ "BP-2026-005", "2026", 1, "财务部", "资本预算", "固定资产购置(设备)",new BigDecimal("1500000.00"),new BigDecimal("1200000.00"), FinBudgetPlan.S_GATHERING },
|
||||
{ "BP-2026-006", "2026", 1, "工程部", "现金流预算", "项目建设投资现金流", new BigDecimal("12000000.00"),new BigDecimal("0.00"), FinBudgetPlan.S_SUBMITTED },
|
||||
};
|
||||
|
||||
for (Object[] row : data) {
|
||||
FinBudgetPlan p = new FinBudgetPlan();
|
||||
p.setPlanCode((String) row[0]);
|
||||
p.setBudgetYear((String) row[1]);
|
||||
p.setRoundNo((Integer) row[2]);
|
||||
p.setDepartment((String) row[3]);
|
||||
p.setBudgetType((String) row[4]);
|
||||
p.setBudgetItem((String) row[5]);
|
||||
p.setProposedAmount((BigDecimal) row[6]);
|
||||
p.setApprovedAmount((BigDecimal) row[7]);
|
||||
p.setVarianceFromTop(((BigDecimal) row[6]).subtract((BigDecimal) row[7]));
|
||||
p.setStatus((String) row[8]);
|
||||
p.setSubmitter("部门负责人");
|
||||
p.setApprover(FinBudgetPlan.S_APPROVED.equals(row[8]) ? "财务总监" : null);
|
||||
p.setSubmitDate("2026-01-15");
|
||||
p.setApprovalDate(FinBudgetPlan.S_APPROVED.equals(row[8]) ? "2026-02-01" : null);
|
||||
p.setJustification("年度预算申报,依据上年实际执行情况及本年业务目标编制");
|
||||
p.setCreatedAt(Instant.now().minus(90, ChronoUnit.DAYS));
|
||||
p.setUpdatedAt(Instant.now().minus(60, ChronoUnit.DAYS));
|
||||
budgetPlanRepo.save(p);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 预算执行记录 =====================
|
||||
private void seedBudgetExecution() {
|
||||
if (budgetExecRepo.count() > 0) return;
|
||||
|
||||
Object[][] data = {
|
||||
// budgetItem, type, period, budgetAmt, actualAmt, dept
|
||||
{ "研发人员人工费用", "费用预算", "2026", new BigDecimal("2200000.00"), new BigDecimal("386500.00"), "研发部" },
|
||||
{ "直接材料采购成本", "成本预算", "2026", new BigDecimal("8100000.00"), new BigDecimal("1623000.00"), "生产部" },
|
||||
{ "办公及行政费用", "费用预算", "2026", new BigDecimal("360000.00"), new BigDecimal("62400.00"), "行政部" },
|
||||
{ "主营业务收入", "收入预算", "2026", new BigDecimal("40000000.00"),new BigDecimal("6830000.00"), "销售部" },
|
||||
{ "固定资产购置(设备)", "资本预算", "2026", new BigDecimal("1200000.00"), new BigDecimal("0.00"), "财务部" },
|
||||
};
|
||||
|
||||
for (Object[] row : data) {
|
||||
FinBudgetExecution e = new FinBudgetExecution();
|
||||
e.setBudgetItem((String) row[0]);
|
||||
e.setBudgetType((String) row[1]);
|
||||
e.setPeriod((String) row[2]);
|
||||
e.setBudgetAmount((BigDecimal) row[3]);
|
||||
e.setActualAmount((BigDecimal) row[4]);
|
||||
BigDecimal variance = ((BigDecimal) row[4]).subtract((BigDecimal) row[3]);
|
||||
e.setVarianceAmount(variance);
|
||||
e.setVarianceRate(((BigDecimal) row[3]).signum() > 0
|
||||
? ((BigDecimal) row[4]).divide((BigDecimal) row[3], 4, java.math.RoundingMode.HALF_UP)
|
||||
.multiply(BigDecimal.valueOf(100)).setScale(2, java.math.RoundingMode.HALF_UP)
|
||||
: BigDecimal.ZERO);
|
||||
e.setOverBudget(variance.signum() > 0);
|
||||
e.setAlerted(variance.signum() > 0);
|
||||
e.setAlertThreshold(BigDecimal.TEN);
|
||||
e.setDepartment((String) row[5]);
|
||||
e.setBudgetVersion("批准版");
|
||||
e.setOperator("admin");
|
||||
budgetExecRepo.save(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user