593 lines
33 KiB
Java
593 lines
33 KiB
Java
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>缺口3:BOM差异自动核算</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=0,total=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=101,BAC 约 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=102,BAC 约 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:凯迪环保项目A(projectId=103,BAC 约 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);
|
||
}
|
||
}
|