Files
ERP/oa-backend/src/main/java/com/kaidi/oa/seed/FinDeptSeeder.java
T
Qiufeng 1affcd9a5e
Signed Release / release (push) Failing after 5m1s
feat: add PostgreSQL web installation wizard
2026-08-04 07:42:20 +08:00

250 lines
14 KiB
Java

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);
}
}
}