生产环节优化

This commit is contained in:
2026-06-11 10:06:26 +08:00
parent b9be88ae3f
commit 3431cc6b17
32 changed files with 2237 additions and 52 deletions

View File

@@ -0,0 +1,57 @@
-- 密炼生产计划维护//晚班
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_production_plan` (
`id` varchar(32) NOT NULL COMMENT '主键',
`sort_no` int DEFAULT NULL COMMENT '排序号',
`machine_id` varchar(32) DEFAULT NULL COMMENT '机台IDmes_xsl_equipment_ledger.id',
`machine_name` varchar(128) DEFAULT NULL COMMENT '机台名称冗余',
`morning_plan_id` varchar(32) DEFAULT NULL COMMENT '早班计划ID母胶/终胶计划',
`morning_plan_type` varchar(2) DEFAULT NULL COMMENT '早班计划类型M母胶/F终胶',
`morning_order_no` varchar(64) DEFAULT NULL COMMENT '早班生产订单',
`morning_order_date` date DEFAULT NULL COMMENT '早班订单日期',
`morning_formula_name` varchar(128) DEFAULT NULL COMMENT '早班配方名称',
`morning_plan_weight` decimal(18,6) DEFAULT NULL COMMENT '早班计划重量',
`morning_planned_car_count` int DEFAULT NULL COMMENT '早班计划车数',
`morning_scheduled_car_count` int DEFAULT NULL COMMENT '早班已排产车数',
`morning_finished_car_count` int DEFAULT NULL COMMENT '早班完成车数',
`morning_plan_count` int DEFAULT NULL COMMENT '早班计划',
`morning_remark` varchar(500) DEFAULT NULL COMMENT '早班备注',
`noon_plan_id` varchar(32) DEFAULT NULL COMMENT '中班计划ID母胶/终胶计划',
`noon_plan_type` varchar(2) DEFAULT NULL COMMENT '中班计划类型M母胶/F终胶',
`noon_order_no` varchar(64) DEFAULT NULL COMMENT '中班生产订单',
`noon_order_date` date DEFAULT NULL COMMENT '中班订单日期',
`noon_formula_name` varchar(128) DEFAULT NULL COMMENT '中班配方名称',
`noon_plan_weight` decimal(18,6) DEFAULT NULL COMMENT '中班计划重量',
`noon_planned_car_count` int DEFAULT NULL COMMENT '中班计划车数',
`noon_scheduled_car_count` int DEFAULT NULL COMMENT '中班已排产车数',
`noon_finished_car_count` int DEFAULT NULL COMMENT '中班完成车数',
`noon_plan_count` int DEFAULT NULL COMMENT '中班计划',
`noon_remark` varchar(500) DEFAULT NULL COMMENT '中班备注',
`night_plan_id` varchar(32) DEFAULT NULL COMMENT '晚班计划ID母胶/终胶计划',
`night_plan_type` varchar(2) DEFAULT NULL COMMENT '晚班计划类型M母胶/F终胶',
`night_order_no` varchar(64) DEFAULT NULL COMMENT '晚班生产订单',
`night_order_date` date DEFAULT NULL COMMENT '晚班订单日期',
`night_formula_name` varchar(128) DEFAULT NULL COMMENT '晚班配方名称',
`night_plan_weight` decimal(18,6) DEFAULT NULL COMMENT '晚班计划重量',
`night_planned_car_count` int DEFAULT NULL COMMENT '晚班计划车数',
`night_scheduled_car_count` int DEFAULT NULL COMMENT '晚班已排产车数',
`night_finished_car_count` int DEFAULT NULL COMMENT '晚班完成车数',
`night_plan_count` int DEFAULT NULL COMMENT '晚班计划',
`night_remark` varchar(500) DEFAULT NULL COMMENT '晚班备注',
`tenant_id` int DEFAULT NULL COMMENT '租户',
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '部门编码',
`create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` int DEFAULT '0' COMMENT '删除标记0正常1删除',
PRIMARY KEY (`id`),
KEY `idx_mxmp_machine` (`machine_id`),
KEY `idx_mxmp_sort` (`sort_no`),
KEY `idx_mxmp_tenant` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES密炼生产计划维护';

View File

@@ -0,0 +1,23 @@
-- 原材料需求计划明细表
CREATE TABLE IF NOT EXISTS `mes_xsl_raw_material_demand_plan` (
`id` varchar(32) NOT NULL COMMENT '主键',
`machine_id` varchar(32) DEFAULT NULL COMMENT '机台ID',
`machine_name` varchar(64) DEFAULT NULL COMMENT '机台名称',
`erp_code` varchar(64) NOT NULL COMMENT 'ERP编号',
`raw_material_name` varchar(128) NOT NULL COMMENT '原材料名称',
`demand_weight` decimal(18,6) DEFAULT '0.000000' COMMENT '需求重量',
`standard_weight` decimal(18,6) DEFAULT '0.000000' COMMENT '标准重量',
`actual_weight` decimal(18,6) DEFAULT '0.000000' COMMENT '实际重量',
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标识(0-正常,1-删除)',
PRIMARY KEY (`id`),
KEY `idx_raw_material_demand_machine` (`machine_name`),
KEY `idx_raw_material_demand_erp` (`erp_code`),
KEY `idx_raw_material_demand_name` (`raw_material_name`),
KEY `idx_raw_material_demand_del` (`del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='原材料需求计划明细';

View File

@@ -0,0 +1,141 @@
package org.jeecg.modules.xslmes.test;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.jeecg.JeecgSystemApplication;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.mes.material.entity.MesMaterial;
import org.jeecg.modules.mes.material.mapper.MesMaterialMapper;
import org.jeecg.modules.xslmes.entity.MesXslFinalBatchPlan;
import org.jeecg.modules.xslmes.entity.MesXslMasterBatchPlan;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
import org.jeecg.modules.xslmes.entity.MesXslProductionOrder;
import org.jeecg.modules.xslmes.mapper.MesXslFinalBatchPlanMapper;
import org.jeecg.modules.xslmes.mapper.MesXslMasterBatchPlanMapper;
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecMapper;
import org.jeecg.modules.xslmes.mapper.MesXslProductionOrderMapper;
import org.jeecg.modules.xslmes.service.IMesXslProductionOrderService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = JeecgSystemApplication.class)
@Transactional
class MesXslProductionOrderSplitIntegrationTest {
@Resource private IMesXslProductionOrderService productionOrderService;
@Resource private MesXslProductionOrderMapper productionOrderMapper;
@Resource private MesXslMasterBatchPlanMapper masterBatchPlanMapper;
@Resource private MesXslFinalBatchPlanMapper finalBatchPlanMapper;
@Resource private MesMaterialMapper materialMapper;
@Resource private MesXslMixingSpecMapper mixingSpecMapper;
@Test
void splitShouldGenerateB1B2AndFWhenSegmentCountIs3() {
String base = "UT" + System.currentTimeMillis();
MesXslProductionOrder order = createOrder(base, 3);
createMaterial("B1" + base + "SA01", "B1-" + base);
createMaterial("B2" + base + "SA01", "B2-" + base);
createMaterial("F" + base + "SA01", "F-" + base);
createMixingSpec("B1" + base + "SA01");
createMixingSpec("B2" + base + "SA01");
createMixingSpec("F" + base + "SA01");
List<MesXslMasterBatchPlan> masters = productionOrderService.splitToMasterBatchPlan(order.getId());
Assertions.assertEquals(2, masters.size(), "段数=3时应生成2条母胶计划");
List<MesXslMasterBatchPlan> dbMasters =
masterBatchPlanMapper.selectList(
new LambdaQueryWrapper<MesXslMasterBatchPlan>()
.eq(MesXslMasterBatchPlan::getSourceOrderId, order.getId())
.orderByAsc(MesXslMasterBatchPlan::getMaterialCode));
Assertions.assertEquals(2, dbMasters.size());
Assertions.assertEquals("B1" + base, dbMasters.get(0).getMaterialCode());
Assertions.assertEquals("B2" + base, dbMasters.get(1).getMaterialCode());
MesXslFinalBatchPlan finalPlan =
finalBatchPlanMapper.selectOne(
new LambdaQueryWrapper<MesXslFinalBatchPlan>()
.eq(MesXslFinalBatchPlan::getSourceOrderId, order.getId())
.last("LIMIT 1"));
Assertions.assertNotNull(finalPlan, "应生成1条终胶计划");
Assertions.assertEquals("F" + base, finalPlan.getMaterialCode());
MesXslProductionOrder updated = productionOrderMapper.selectById(order.getId());
Assertions.assertEquals(1, updated.getSplitStatus());
}
@Test
void splitShouldFailWhenAnyMixingSpecMissing() {
String base = "UT" + (System.currentTimeMillis() + 7);
MesXslProductionOrder order = createOrder(base, 3);
createMaterial("B1" + base + "SA01", "B1-" + base);
createMaterial("B2" + base + "SA01", "B2-" + base);
createMaterial("F" + base + "SA01", "F-" + base);
// 故意缺少 FxxxSA01
createMixingSpec("B1" + base + "SA01");
createMixingSpec("B2" + base + "SA01");
JeecgBootException ex =
Assertions.assertThrows(
JeecgBootException.class,
() -> productionOrderService.splitToMasterBatchPlan(order.getId()));
Assertions.assertEquals("对应物料的混炼示方不存在,请先生成混炼示方!", ex.getMessage());
List<MesXslMasterBatchPlan> dbMasters =
masterBatchPlanMapper.selectList(
new LambdaQueryWrapper<MesXslMasterBatchPlan>()
.eq(MesXslMasterBatchPlan::getSourceOrderId, order.getId()));
Assertions.assertTrue(dbMasters.isEmpty(), "失败后母胶计划应回滚");
MesXslFinalBatchPlan finalPlan =
finalBatchPlanMapper.selectOne(
new LambdaQueryWrapper<MesXslFinalBatchPlan>()
.eq(MesXslFinalBatchPlan::getSourceOrderId, order.getId())
.last("LIMIT 1"));
Assertions.assertNull(finalPlan, "失败后终胶计划应回滚");
MesXslProductionOrder unchanged = productionOrderMapper.selectById(order.getId());
Assertions.assertTrue(
unchanged.getSplitStatus() == null || unchanged.getSplitStatus() == 0, "失败后拆分状态不应置为已拆分");
}
private MesXslProductionOrder createOrder(String baseCode, int segmentCount) {
MesXslProductionOrder order = new MesXslProductionOrder();
order.setProductionOrderNo("PO-" + baseCode);
order.setOrderDate(new Date());
order.setProcessSegmentCount(segmentCount);
order.setMesMaterialName(baseCode);
order.setMaterialCode(baseCode);
order.setPlanQty(new BigDecimal("100.00"));
order.setSplitStatus(0);
order.setDelFlag(0);
productionOrderMapper.insert(order);
return order;
}
private void createMaterial(String code, String name) {
MesMaterial material = new MesMaterial();
material.setMaterialCode(code);
material.setMaterialName(name);
material.setDelFlag(0);
materialMapper.insert(material);
}
private void createMixingSpec(String specName) {
MesXslMixingSpec spec = new MesXslMixingSpec();
spec.setSpecName(specName);
spec.setDelFlag(0);
mixingSpecMapper.insert(spec);
}
}