Files
ERP/oa-backend/src/main/java/com/kaidi/oa/seed/CostCtrlGapSeeder.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

593 lines
33 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.kaidi.oa.seed;
import com.kaidi.oa.common.Money;
import com.kaidi.oa.domain.BomVarianceDetail;
import com.kaidi.oa.domain.HrLaborContract;
import com.kaidi.oa.domain.MaterialIssue;
import com.kaidi.oa.domain.MultiPaymentBatch;
import com.kaidi.oa.domain.MultiPaymentBatchItem;
import com.kaidi.oa.domain.ProductionReport;
import com.kaidi.oa.domain.ProjectBudgetLine;
import com.kaidi.oa.domain.RdEbom;
import com.kaidi.oa.repository.BomVarianceDetailRepository;
import com.kaidi.oa.repository.HrLaborContractRepository;
import com.kaidi.oa.repository.MaterialIssueRepository;
import com.kaidi.oa.repository.MultiPaymentBatchItemRepository;
import com.kaidi.oa.repository.MultiPaymentBatchRepository;
import com.kaidi.oa.repository.ProductionReportRepository;
import com.kaidi.oa.repository.ProjectBudgetLineRepository;
import com.kaidi.oa.repository.RdEbomRepository;
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;
/**
* 成本控制部 W7 可建缺口种子数据(@Order 215)。
*
* <p>一次性补齐三条 med 级 PARTIAL 缺口所需的演示数据:
* <ol>
* <li><b>缺口3BOM差异自动核算</b> —— BomVarianceDetail 表无数据导致 drill 下钻 404、
* dashboard 全 0、OA 审批流差异原因标记无可标数据。本 Seeder 写入 8 条跨状态
* (正常/黄色预警/红色超标)、跨期间、已标记/未标记原因的真实差异明细,
* 五维差异字段手工按公式填入(与服务端 BomVarianceDetailController.recompute 一致)。</li>
* <li><b>缺口4:项目成本控制(EVM 400</b> —— ProjectBudgetLine 无数据导致
* GET /project-budget-lines/evm?projectName=xxx 返回 404,前端 EVM 卡片无法计算。
* 本 Seeder 写入 12 条跨项目 WBS 预算行(含执行中状态,actualAmount 已回填),
* 同时写入 ProductionReport 4 条报工数据(支持 @Scheduled 凌晨 2 点成本归集任务),
* 写入 MultiPaymentBatch 3 条(跨状态含已审批含明细行)消除 count=0 缺口。</li>
* <li><b>缺口8:跨部门接口</b> —— HrLaborContract 无签署合同导致
* POST /cost-cross-dept/sync-labor-rate 返回空同步(0条);
* RdEbom 无已变更/已发布条目导致 POST /cost-cross-dept/ebom-to-bom-signoff 返回 400。
* 本 Seeder 写入 6 条已签署劳动合同(各部门覆盖)和 6 条 RdEbom 节点
* devProjectId=1,含已发布状态),满足联动触发条件。</li>
* </ol>
*
* 幂等:各表 count() > 0 则跳过,重启安全。
*/
@DemoSeed
@Order(215)
public class CostCtrlGapSeeder implements ApplicationRunner {
private final BomVarianceDetailRepository varRepo;
private final ProjectBudgetLineRepository budgetRepo;
private final ProductionReportRepository reportRepo;
private final HrLaborContractRepository hrRepo;
private final RdEbomRepository ebomRepo;
private final MultiPaymentBatchRepository batchRepo;
private final MultiPaymentBatchItemRepository batchItemRepo;
private final MaterialIssueRepository issueRepo;
public CostCtrlGapSeeder(
BomVarianceDetailRepository varRepo,
ProjectBudgetLineRepository budgetRepo,
ProductionReportRepository reportRepo,
HrLaborContractRepository hrRepo,
RdEbomRepository ebomRepo,
MultiPaymentBatchRepository batchRepo,
MultiPaymentBatchItemRepository batchItemRepo,
MaterialIssueRepository issueRepo) {
this.varRepo = varRepo;
this.budgetRepo = budgetRepo;
this.reportRepo = reportRepo;
this.hrRepo = hrRepo;
this.ebomRepo = ebomRepo;
this.batchRepo = batchRepo;
this.batchItemRepo = batchItemRepo;
this.issueRepo = issueRepo;
}
@Override
@Transactional
public void run(ApplicationArguments args) {
seedBomVarianceDetails();
seedProjectBudgetLines();
seedProductionReports();
seedMaterialIssues();
seedHrLaborContracts();
seedRdEboms();
seedMultiPaymentBatches();
}
// ======================================================================
// 1. BOM 差异五维明细(8 条,跨状态/期间/已标记原因)
// ======================================================================
private void seedBomVarianceDetails() {
if (varRepo.count() > 0) return;
// 1) 钢材-用量超标-黄色预警(用量差异率 7.5%)
bvd("WO-2025-101", "凯迪生物质锅炉项目", "Q235B 钢材", "2025-06",
80.0, 86.0, new BigDecimal("6100.00"), new BigDecimal("6100.00"),
0.02, 0.025, 80.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
8.0, 8.2, new BigDecimal("47.62"),
"供应商提价", "加工切割损耗比定额高 0.5%", "张会计",
// 五维差异手工计算:qtyVar=(86-80)*6100=36600, priceVar=0, lossVar=(0.025-0.02)*80*6100=2440
// routeVar=(8.2-8)*47.62=9.52, totalVar=39049.52, diffStatus=黄色预警(用量率7.5%)
new BigDecimal("36600.00"), BigDecimal.ZERO, new BigDecimal("2440.00"),
BigDecimal.ZERO, new BigDecimal("9.52"), new BigDecimal("39049.52"),
"黄色预警", new BigDecimal("7.50"), new BigDecimal("0.00"));
// 2) 螺旋输送机叶片-替代料差异-正常
bvd("WO-2025-102", "凯迪水处理工程", "螺旋输送机叶片", "2025-06",
10.0, 10.0, new BigDecimal("3800.00"), new BigDecimal("3800.00"),
0.01, 0.01, 10.0, true, new BigDecimal("38500.00"), new BigDecimal("38000.00"),
4.0, 4.0, new BigDecimal("47.62"),
"材料代用", "因货期紧张使用加厚型替代,单件成本增加50元", "李成本",
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO,
new BigDecimal("500.00"), BigDecimal.ZERO, new BigDecimal("500.00"),
"正常", BigDecimal.ZERO, BigDecimal.ZERO);
// 3) PAC 絮凝剂-价格超标-红色超标(价格差异率 14.2%)
bvd("WO-2025-103", "凯迪环保项目A", "聚合氯化铝(PAC", "2025-06",
20.0, 21.0, new BigDecimal("2060.00"), new BigDecimal("2180.00"),
0.01, 0.012, 20.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
1.5, 1.5, new BigDecimal("53.57"),
"供应商提价", "原料成本上涨,供应商单价上调5.8%,超过成本控制阈值", "王成本",
// qtyVar=(21-20)*2060=2060; priceVar=(2180-2060)*21=2520; lossVar=(0.012-0.01)*20*2060=824
// routeVar=0; total=5404; priceRate=2520/(2060*21)*100=5.82%
// 差异判断:总差异5404+较高超成本→红色(>50000阈值用totalVar,但5404<50000,用qtyRate判)
// 实际 qtyRate = 2060/(2060*20)*100 = 5%,与下面rate一致
new BigDecimal("2060.00"), new BigDecimal("2520.00"), new BigDecimal("824.00"),
BigDecimal.ZERO, BigDecimal.ZERO, new BigDecimal("5404.00"),
"黄色预警", new BigDecimal("5.00"), new BigDecimal("5.82"));
// 4) ABB 变频器-用量&价格双超-红色超标
bvd("WO-2025-104", "凯迪技改项目", "ABB变频器ACS550 37kW", "2025-06",
3.0, 4.0, new BigDecimal("16800.00"), new BigDecimal("18900.00"),
0.0, 0.0, 0.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
16.0, 18.0, new BigDecimal("71.43"),
"操作浪费", "采购多订1台备用,未经成本控制部批准", "赵成本",
// qtyVar=(4-3)*16800=16800; priceVar=(18900-16800)*4=8400; routeVar=(18-16)*71.43=142.86
// total=25342.86; qtyRate=16800/(16800*3)*100=33.3% → 红色超标
new BigDecimal("16800.00"), new BigDecimal("8400.00"), BigDecimal.ZERO,
BigDecimal.ZERO, new BigDecimal("142.86"), new BigDecimal("25342.86"),
"红色超标", new BigDecimal("33.33"), new BigDecimal("12.50"));
// 5) PE给水管-2025-05期间-正常(历史数据,供跨期间对比)
bvd("WO-2025-098", "凯迪水处理工程", "PE100给水管 DN200", "2025-05",
200.0, 198.0, new BigDecimal("370.00"), new BigDecimal("385.00"),
0.02, 0.018, 200.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
3.0, 2.8, new BigDecimal("53.57"),
null, null, "李成本",
// qtyVar=(198-200)*370=-740; priceVar=(385-370)*198=2970; lossVar=(0.018-0.02)*200*370=-1480
// routeVar=(2.8-3)*53.57=-10.714; total=739.286
// qtyRate=-740/(370*200)*100=-1%|1|<5 → 正常
new BigDecimal("-740.00"), new BigDecimal("2970.00"), new BigDecimal("-1480.00"),
BigDecimal.ZERO, new BigDecimal("-10.71"), new BigDecimal("739.29"),
"正常", new BigDecimal("-1.00"), new BigDecimal("4.05"));
// 6) 焊丝焊条-未标记原因-正常(供前端"未标记"场景演示)
bvd("WO-2025-105", "凯迪生物质锅炉项目", "碳钢焊丝 ER70S-6", "2026-05",
50.0, 52.0, new BigDecimal("85.00"), new BigDecimal("88.00"),
0.03, 0.033, 50.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
12.0, 12.5, new BigDecimal("47.62"),
null, null, "赵成本",
// qtyVar=(52-50)*85=170; priceVar=(88-85)*52=156; lossVar=(0.033-0.03)*50*85=12.75
// routeVar=(12.5-12)*47.62=23.81; total=362.56; qtyRate=170/(85*50)*100=4%
new BigDecimal("170.00"), new BigDecimal("156.00"), new BigDecimal("12.75"),
BigDecimal.ZERO, new BigDecimal("23.81"), new BigDecimal("362.56"),
"正常", new BigDecimal("4.00"), new BigDecimal("3.53"));
// 7) 设备故障导致工时超标-黄色预警(工艺路线差异为主)
bvd("WO-2026-001", "凯迪技改项目", "液压折弯机外协加工", "2026-05",
5.0, 5.0, new BigDecimal("1200.00"), new BigDecimal("1200.00"),
0.0, 0.0, 0.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
20.0, 32.0, new BigDecimal("71.43"),
"设备故障", "折弯机液压泵故障停机8小时,工时超标60%", "李成本",
// qtyVar=0; priceVar=0; lossVar=0; routeVar=(32-20)*71.43=857.16; total=857.16
// qtyRate=0total=857.16<10000,但工时超60%,标黄色预警(超标10000阈值未到,但差异率>5%按工时口径)
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO,
BigDecimal.ZERO, new BigDecimal("857.16"), new BigDecimal("857.16"),
"正常", BigDecimal.ZERO, BigDecimal.ZERO);
// 8) 工艺改进节约-负差异-正常(正向节约,totalVariance<0
bvd("WO-2026-002", "凯迪水处理工程", "不锈钢316L管件", "2026-06",
30.0, 28.0, new BigDecimal("450.00"), new BigDecimal("420.00"),
0.02, 0.015, 30.0, false, BigDecimal.ZERO, BigDecimal.ZERO,
6.0, 5.0, new BigDecimal("53.57"),
"工艺改进", "引入激光切割替代手工切割,用量节省2件,工时节约1小时", "张会计",
// qtyVar=(28-30)*450=-900; priceVar=(420-450)*28=-840; lossVar=(0.015-0.02)*30*450=-67.5
// routeVar=(5-6)*53.57=-53.57; total=-1861.07 → 正常(节约有利差异)
new BigDecimal("-900.00"), new BigDecimal("-840.00"), new BigDecimal("-67.50"),
BigDecimal.ZERO, new BigDecimal("-53.57"), new BigDecimal("-1861.07"),
"正常", new BigDecimal("-6.67"), new BigDecimal("-6.67"));
}
private void bvd(String workOrderCode, String projectName, String materialName, String period,
double stdQty, double actualQty, BigDecimal stdPrice, BigDecimal actualPrice,
double stdLossRate, double actualLossRate, double inputQty,
boolean isSubstitute, BigDecimal substituteCost, BigDecimal originalStdCost,
double stdLaborHours, double actualLaborHours, BigDecimal stdLaborRate,
String reasonTag, String reasonNote, String operator,
BigDecimal qtyVariance, BigDecimal priceVariance, BigDecimal lossVariance,
BigDecimal substituteVariance, BigDecimal routingVariance, BigDecimal totalVariance,
String diffStatus, BigDecimal qtyVarianceRate, BigDecimal priceVarianceRate) {
BomVarianceDetail d = new BomVarianceDetail();
d.setWorkOrderCode(workOrderCode);
d.setProjectName(projectName);
d.setMaterialName(materialName);
d.setPeriod(period);
d.setStdQty(stdQty);
d.setActualQty(actualQty);
d.setStdPrice(stdPrice);
d.setActualPrice(actualPrice);
d.setStdLossRate(stdLossRate);
d.setActualLossRate(actualLossRate);
d.setInputQty(inputQty);
d.setSubstitute(isSubstitute);
d.setSubstituteCost(substituteCost);
d.setOriginalStdCost(originalStdCost);
d.setStdLaborHours(stdLaborHours);
d.setActualLaborHours(actualLaborHours);
d.setStdLaborRate(stdLaborRate);
d.setReasonTag(reasonTag);
d.setReasonNote(reasonNote);
d.setOperator(operator);
d.setQtyVariance(qtyVariance);
d.setPriceVariance(priceVariance);
d.setLossVariance(lossVariance);
d.setSubstituteVariance(substituteVariance);
d.setRoutingVariance(routingVariance);
d.setTotalVariance(totalVariance);
d.setDiffStatus(diffStatus);
d.setQtyVarianceRate(qtyVarianceRate);
d.setPriceVarianceRate(priceVarianceRate);
d.setCreatedAt(Instant.now().minus(30, ChronoUnit.DAYS));
varRepo.save(d);
}
// ======================================================================
// 2. WBS 预算行(12 条,3 个项目,含执行中状态和已有 actual)
// ======================================================================
private void seedProjectBudgetLines() {
if (budgetRepo.count() > 0) return;
// 项目1:凯迪生物质锅炉项目(projectId=101BAC 约 720 万)
pbl(101L, "凯迪生物质锅炉项目", "WBS-1.1", "主体钢结构制造", "材料费",
new BigDecimal("3200000.00"), new BigDecimal("2800000.00"), new BigDecimal("2600000.00"),
"执行中", "张工", "凯迪科技有限公司", "钢材+配套件");
pbl(101L, "凯迪生物质锅炉项目", "WBS-1.2", "焊接人工", "人工费",
new BigDecimal("480000.00"), new BigDecimal("460000.00"), new BigDecimal("390000.00"),
"执行中", "李工", "凯迪科技有限公司", "焊工工时费");
pbl(101L, "凯迪生物质锅炉项目", "WBS-1.3", "设备吊装机械", "机械费",
new BigDecimal("280000.00"), new BigDecimal("260000.00"), new BigDecimal("210000.00"),
"执行中", "王工", "凯迪科技有限公司", "起重机租赁费");
pbl(101L, "凯迪生物质锅炉项目", "WBS-1.4", "保温外护分包", "分包费",
new BigDecimal("320000.00"), new BigDecimal("310000.00"), new BigDecimal("0.00"),
"已下达", "赵工", "凯迪科技有限公司", "保温工程专业分包");
pbl(101L, "凯迪生物质锅炉项目", "WBS-1.5", "项目管理费", "间接费",
new BigDecimal("180000.00"), new BigDecimal("0.00"), new BigDecimal("120000.00"),
"执行中", "孙工", "凯迪科技有限公司", "管理人员工资+办公费");
// 项目2:凯迪水处理工程(projectId=102BAC 约 480 万)
pbl(102L, "凯迪水处理工程", "WBS-2.1", "水处理设备采购", "材料费",
new BigDecimal("1800000.00"), new BigDecimal("1780000.00"), new BigDecimal("1650000.00"),
"执行中", "陈工", "凯迪生态科技有限公司", "净水设备+管材");
pbl(102L, "凯迪水处理工程", "WBS-2.2", "安装调试人工", "人工费",
new BigDecimal("360000.00"), new BigDecimal("340000.00"), new BigDecimal("290000.00"),
"执行中", "周工", "凯迪生态科技有限公司", "安装工程队人工");
pbl(102L, "凯迪水处理工程", "WBS-2.3", "基建土建分包", "分包费",
new BigDecimal("620000.00"), new BigDecimal("600000.00"), new BigDecimal("580000.00"),
"执行中", "吴工", "凯迪生态科技有限公司", "土建专业分包");
pbl(102L, "凯迪水处理工程", "WBS-2.4", "其他直接费", "其他直接费",
new BigDecimal("140000.00"), new BigDecimal("120000.00"), new BigDecimal("98000.00"),
"执行中", "郑工", "凯迪生态科技有限公司", "测试费+运输费");
// 项目3:凯迪环保项目AprojectId=103BAC 约 250 万,超支预警项目)
pbl(103L, "凯迪环保项目A", "WBS-3.1", "药剂原材料", "材料费",
new BigDecimal("800000.00"), new BigDecimal("780000.00"), new BigDecimal("870000.00"),
"执行中", "冯工", "凯迪科技有限公司", "PAC/PAM药剂采购,价格上涨中");
pbl(103L, "凯迪环保项目A", "WBS-3.2", "运营维护人工", "人工费",
new BigDecimal("350000.00"), new BigDecimal("320000.00"), new BigDecimal("360000.00"),
"执行中", "蒋工", "凯迪科技有限公司", "运营人员工资(超编2人)");
pbl(103L, "凯迪环保项目A", "WBS-3.3", "设备维修机械费", "机械费",
new BigDecimal("280000.00"), new BigDecimal("0.00"), new BigDecimal("310000.00"),
"执行中", "沈工", "凯迪科技有限公司", "设备检修费超预算(设备故障多)");
}
private void pbl(Long projectId, String projectName, String wbsCode, String wbsName, String element,
BigDecimal budgetAmount, BigDecimal committedAmount, BigDecimal actualAmount,
String status, String owner, String companySubject, String note) {
ProjectBudgetLine l = new ProjectBudgetLine();
l.setProjectId(projectId);
l.setProjectName(projectName);
l.setWbsCode(wbsCode);
l.setWbsName(wbsName);
l.setElement(element);
l.setBudgetAmount(budgetAmount);
l.setCommittedAmount(committedAmount);
l.setActualAmount(actualAmount);
l.setStatus(status);
l.setOwner(owner);
l.setCompanySubject(companySubject);
l.setNote(note);
l.setCreatedAt(Instant.now().minus(90, ChronoUnit.DAYS));
budgetRepo.save(l);
}
// ======================================================================
// 3. 报工记录(4 条,支持 @Scheduled 成本归集 + 跨模块联动验证)
// ======================================================================
private void seedProductionReports() {
if (reportRepo.count() > 0) return;
report("BG-2026-001", 1001L, "WO-2025-101", "凯迪生物质锅炉项目", "焊接",
"锅炉车间", 5.0, 5.0, 0.0, 168.0,
new BigDecimal("47.62"), Money.of(47.62 * 168), "李焊工", "2026-05-10", "有效");
report("BG-2026-002", 1001L, "WO-2025-101", "凯迪生物质锅炉项目", "组装",
"装配车间", 5.0, 5.0, 0.0, 80.0,
new BigDecimal("47.62"), Money.of(47.62 * 80), "张装配", "2026-05-20", "有效");
report("BG-2026-003", 1002L, "WO-2025-103", "凯迪水处理工程", "下料",
"切割车间", 8.0, 8.0, 0.0, 48.0,
new BigDecimal("47.62"), Money.of(47.62 * 48), "王下料", "2026-06-01", "有效");
report("BG-2026-004", 1003L, "WO-2026-001", "凯迪环保项目A", "调试",
"调试班组", 3.0, 3.0, 0.0, 32.0,
new BigDecimal("53.57"), Money.of(53.57 * 32), "赵调试", "2026-06-05", "有效");
}
private void report(String reportNo, Long workOrderId, String workOrderNo, String projectName,
String process, String workshop, double qty, double qualifiedQty, double scrapQty,
double laborHours, BigDecimal laborRate, BigDecimal laborCost,
String reporter, String reportDate, String status) {
ProductionReport r = new ProductionReport();
r.setReportNo(reportNo);
r.setWorkOrderId(workOrderId);
r.setWorkOrderNo(workOrderNo);
r.setProjectName(projectName);
r.setProcess(process);
r.setWorkshop(workshop);
r.setQty(qty);
r.setQualifiedQty(qualifiedQty);
r.setScrapQty(scrapQty);
r.setLaborHours(laborHours);
r.setLaborRate(laborRate);
r.setLaborCost(laborCost);
r.setReporter(reporter);
r.setReportDate(reportDate);
r.setStatus(status);
r.setCreatedAt(Instant.now().minus(15, ChronoUnit.DAYS));
reportRepo.save(r);
}
// ======================================================================
// 4. 领料记录(4 条,与 BomVarianceDetail 同工单,支持 drill 下钻)
// ======================================================================
private void seedMaterialIssues() {
if (issueRepo.count() > 0) return;
issue("MI-2025-001", 1001L, "WO-2025-101", "凯迪生物质锅炉项目",
"Q235B 钢材", "吨", 86.0,
new BigDecimal("6100.00"), Money.of(86.0 * 6100), "有效", "2025-06-10", "张会计");
issue("MI-2025-002", 1002L, "WO-2025-103", "凯迪环保项目A",
"聚合氯化铝(PAC", "吨", 21.0,
new BigDecimal("2180.00"), Money.of(21.0 * 2180), "有效", "2025-06-15", "王成本");
issue("MI-2025-003", 1003L, "WO-2025-104", "凯迪技改项目",
"ABB变频器ACS550 37kW", "台", 4.0,
new BigDecimal("18900.00"), Money.of(4.0 * 18900), "有效", "2025-06-20", "赵成本");
issue("MI-2026-001", 1004L, "WO-2026-002", "凯迪水处理工程",
"不锈钢316L管件", "件", 28.0,
new BigDecimal("420.00"), Money.of(28.0 * 420), "有效", "2026-06-03", "张会计");
}
private void issue(String issueNo, Long workOrderId, String workOrderNo, String projectName,
String materialName, String unit, double qty,
BigDecimal unitPrice, BigDecimal amount,
String status, String issueDate, String operator) {
MaterialIssue mi = new MaterialIssue();
mi.setIssueNo(issueNo);
mi.setWorkOrderId(workOrderId);
mi.setWorkOrderNo(workOrderNo);
mi.setProjectName(projectName);
mi.setMaterialName(materialName);
mi.setUnit(unit);
mi.setQty(qty);
mi.setUnitPrice(unitPrice);
mi.setAmount(amount);
mi.setStatus(status);
mi.setIssueDate(issueDate);
mi.setOperator(operator);
mi.setCreatedAt(Instant.now().minus(20, ChronoUnit.DAYS));
issueRepo.save(mi);
}
// ======================================================================
// 5. 已签署劳动合同(6 条,覆盖生产/成控/研发/运营各部门)
// 消除 POST /cost-cross-dept/sync-labor-rate 返回空(0条)缺口
// ======================================================================
private void seedHrLaborContracts() {
if (hrRepo.count() > 0) return;
hrContract("LC-2024-001", "张伟", "EMP-0021", "生产部", "固定期限劳动合同", "3年",
"2024-01-01", "2026-12-31", "已签署", "2024-01-03", "BATCH-2024-01", null);
hrContract("LC-2024-002", "刘洋", "EMP-0032", "生产部", "固定期限劳动合同", "3年",
"2024-01-01", "2026-12-31", "已签署", "2024-01-03", "BATCH-2024-01", null);
hrContract("LC-2024-003", "王芳", "EMP-0045", "成本控制部", "固定期限劳动合同", "3年",
"2024-03-01", "2027-02-28", "已签署", "2024-03-02", "BATCH-2024-03", null);
hrContract("LC-2024-004", "欧阳明", "EMP-0058", "研发中心", "无固定期限劳动合同", "长期",
"2024-06-01", null, "已签署", "2024-06-03", "BATCH-2024-06", null);
hrContract("LC-2025-001", "赵静", "EMP-0072", "水处理运营中心", "固定期限劳动合同", "2年",
"2025-01-01", "2026-12-31", "已签署", "2025-01-06", "BATCH-2025-01", null);
hrContract("LC-2025-002", "陈磊", "EMP-0086", "生产部", "劳务协议", "1年",
"2025-04-01", "2026-03-31", "已签署", "2025-04-02", "BATCH-2025-04", null);
}
private void hrContract(String contractNo, String employeeName, String employeeNo, String dept,
String contractType, String term, String startDate, String expireDate,
String status, String signDate, String batchId, Long prevContractId) {
HrLaborContract c = new HrLaborContract();
c.setContractNo(contractNo);
c.setEmployeeName(employeeName);
c.setEmployeeNo(employeeNo);
c.setDept(dept);
c.setContractType(contractType);
c.setTerm(term);
c.setStartDate(startDate);
c.setExpireDate(expireDate);
c.setStatus(status);
c.setSignDate(signDate);
c.setBatchId(batchId);
c.setPrevContractId(prevContractId);
c.setCreatedAt(Instant.now().minus(180, ChronoUnit.DAYS));
c.setUpdatedAt(Instant.now().minus(30, ChronoUnit.DAYS));
hrRepo.save(c);
}
// ======================================================================
// 6. EBOM 节点(6 条,devProjectId=1,含已发布/已变更状态)
// 消除 POST /cost-cross-dept/ebom-to-bom-signoff 返回 400 缺口
// ======================================================================
private void seedRdEboms() {
if (ebomRepo.count() > 0) return;
// 产品根节点(已发布)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", null, "产品", "KD-BOILER-001",
"凯迪生物质蒸汽锅炉(6T/H", "套", "6T/H 10Bar", 1.0, "V2.1", "已发布", 1, "张工");
// 主体钢结构(已变更—触发会签)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", 1L, "部件", "KD-STRUCT-001",
"锅炉主体钢结构", "套", "Q235B δ=10mm", 1.0, "V2.1", "已变更", 2, "张工");
// 燃烧器(已发布—触发会签)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", 1L, "部件", "KD-BURNER-001",
"生物质燃烧器", "台", "额定热功率 4.5MW", 1.0, "V2.0", "已发布", 3, "张工");
// 炉管(草稿,不触发会签)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", 1L, "部件", "KD-TUBE-001",
"锅炉水冷壁管束", "组", "20#钢 φ51×4", 1.0, "V1.0", "草稿", 4, "李工");
// 钢材(已变更—触发会签)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", 2L, "零件", "MAT-STEEL-001",
"Q235B钢板", "吨", "δ=10mm 1500×6000", 80.0, "V2.1", "已变更", 5, "张工");
// 标准螺栓(已发布)
ebom(1L, "凯迪生物质蒸汽锅炉(6T/H", 2L, "标准件", "STD-BOLT-M20",
"M20六角头螺栓", "件", "GB/T 5782 M20×60", 240.0, "V2.0", "已发布", 6, "张工");
}
private void ebom(Long devProjectId, String productName, Long parentId, String level,
String matCode, String matName, String unit, String spec,
double qty, String version, String status, int seq, String createdBy) {
RdEbom e = new RdEbom();
e.setDevProjectId(devProjectId);
e.setProductName(productName);
e.setParentId(parentId);
e.setLevel(level);
e.setMatCode(matCode);
e.setMatName(matName);
e.setUnit(unit);
e.setSpec(spec);
e.setQty(qty);
e.setVersion(version);
e.setStatus(status);
e.setSeq(seq);
e.setCreatedBy(createdBy);
e.setCreatedAt(Instant.now().minus(60, ChronoUnit.DAYS));
ebomRepo.save(e);
}
// ======================================================================
// 7. 一对多进度款批次(3 条,跨状态,含明细行)
// 消除 multi-payment-batches count=0 缺口
// ======================================================================
private void seedMultiPaymentBatches() {
if (batchRepo.count() > 0) return;
// 批次1:已批准-含3个人材机子项(正常完整批次演示)
MultiPaymentBatch b1 = new MultiPaymentBatch();
b1.setBatchCode("MPB-2026-001");
b1.setTitle("凯迪生物质锅炉项目2026年5月进度款");
b1.setProjectName("凯迪生物质锅炉项目");
b1.setPayerName("凯迪科技有限公司");
b1.setPayeeName("华钢物资有限公司");
b1.setTotalRequestAmount(new BigDecimal("528000.00"));
b1.setStatus("已批准");
b1.setApplicant("张工");
b1.setApprover("李总");
b1.setApprovalComment("已核实现场进度,材料发货凭证齐全,同意支付");
b1.setNote("包含钢材款+运费+装卸费3项");
b1.setCreatedAt(Instant.now().minus(30, ChronoUnit.DAYS));
b1 = batchRepo.save(b1);
batchItem(b1.getId(), 1001L, "人材机流程", "Q235B钢材 50吨采购款",
new BigDecimal("305000.00"), new BigDecimal("290000.00"), new BigDecimal("290000.00"), "一期50吨钢材");
batchItem(b1.getId(), 1002L, "人材机流程", "螺旋输送机叶片 10件",
new BigDecimal("39000.00"), new BigDecimal("39000.00"), new BigDecimal("39000.00"), "批量采购10件");
batchItem(b1.getId(), 1003L, "人材机流程", "PE给水管200根运费",
new BigDecimal("800.00"), new BigDecimal("800.00"), new BigDecimal("800.00"), "到货运费");
// 批次2:审批中(演示在途流程可见性)
MultiPaymentBatch b2 = new MultiPaymentBatch();
b2.setBatchCode("MPB-2026-002");
b2.setTitle("凯迪水处理工程2026年6月进度款");
b2.setProjectName("凯迪水处理工程");
b2.setPayerName("凯迪生态科技有限公司");
b2.setPayeeName("浙江联塑管道");
b2.setTotalRequestAmount(new BigDecimal("77000.00"));
b2.setStatus("审批中");
b2.setApplicant("陈工");
b2.setNote("PE管道第二批次进度款,含增值税发票");
b2.setCreatedAt(Instant.now().minus(7, ChronoUnit.DAYS));
b2 = batchRepo.save(b2);
batchItem(b2.getId(), 2001L, "人材机流程", "PE100给水管200根第2批",
new BigDecimal("77000.00"), new BigDecimal("77000.00"), new BigDecimal("77000.00"), "第2批货已到场");
// 批次3:草稿(演示新建编辑状态)
MultiPaymentBatch b3 = new MultiPaymentBatch();
b3.setBatchCode("MPB-2026-003");
b3.setTitle("凯迪环保项目A药剂款汇总");
b3.setProjectName("凯迪环保项目A");
b3.setPayerName("凯迪科技有限公司");
b3.setPayeeName("江苏清河水处理材料");
b3.setTotalRequestAmount(new BigDecimal("45780.00"));
b3.setStatus("草稿");
b3.setApplicant("王成本");
b3.setNote("将3批PAC采购进度款合并一次支付");
b3.setCreatedAt(Instant.now().minus(1, ChronoUnit.DAYS));
b3 = batchRepo.save(b3);
batchItem(b3.getId(), 3001L, "人材机流程", "PAC絮凝剂第1批20吨",
new BigDecimal("43600.00"), new BigDecimal("43600.00"), new BigDecimal("43600.00"), "已入库");
batchItem(b3.getId(), 3002L, "人材机流程", "运费及装卸费",
new BigDecimal("2180.00"), new BigDecimal("2180.00"), new BigDecimal("2180.00"), "发票已到");
}
private void batchItem(Long batchId, Long sourcePaymentId, String sourceType,
String sourceDesc, BigDecimal invoicedAmount,
BigDecimal paidAmount, BigDecimal requestAmount, String note) {
MultiPaymentBatchItem item = new MultiPaymentBatchItem();
item.setBatchId(batchId);
item.setSourcePaymentId(sourcePaymentId);
item.setSourceType(sourceType);
item.setSourceDesc(sourceDesc);
item.setInvoicedAmount(invoicedAmount);
item.setPaidAmount(paidAmount);
item.setRequestAmount(requestAmount);
item.setNote(note);
item.setCreatedAt(Instant.now().minus(7, ChronoUnit.DAYS));
batchItemRepo.save(item);
}
}