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,593 @@
|
||||
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.stereotype.Component;
|
||||
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 则跳过,重启安全。
|
||||
*/
|
||||
@Component
|
||||
@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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user