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.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) 之后运行。 */ @DemoSeed @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); } } }