贴皮新增面积计算、贴皮排单新增面积统计

This commit is contained in:
gaoqr
2026-07-29 14:09:07 +08:00
parent 45ef5b9c6a
commit b0a46d6f37
9 changed files with 66 additions and 40 deletions
@@ -211,6 +211,7 @@ public class ErrorCodeConstants {
public static final ErrorCode VENEER_PLAN_PLATE_SOURCE_MISMATCH = new ErrorCode(1_003_009_049, "veneer.plan.plate.source.mismatch"); public static final ErrorCode VENEER_PLAN_PLATE_SOURCE_MISMATCH = new ErrorCode(1_003_009_049, "veneer.plan.plate.source.mismatch");
public static final ErrorCode VENEER_PLAN_PLATE_STATUS_CHANGED = new ErrorCode(1_003_009_050, "veneer.plan.plate.status.changed"); public static final ErrorCode VENEER_PLAN_PLATE_STATUS_CHANGED = new ErrorCode(1_003_009_050, "veneer.plan.plate.status.changed");
public static final ErrorCode VENEER_DECOMPOSE_RECORD_INSERT_FAILED = new ErrorCode(1_003_009_051, "veneer.decompose.record.insert.failed"); public static final ErrorCode VENEER_DECOMPOSE_RECORD_INSERT_FAILED = new ErrorCode(1_003_009_051, "veneer.decompose.record.insert.failed");
public static final ErrorCode VENEER_DECOMPOSE_PLATE_SIZE_INVALID = new ErrorCode(1_003_009_052, "veneer.decompose.plate.size.invalid");
//=========== 部件管理 1-003-010-000 ============ //=========== 部件管理 1-003-010-000 ============
public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist"); public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist");
@@ -59,12 +59,12 @@ public class OrderPlateVeneerDO extends BaseDO {
private String plateName; private String plateName;
/** /**
* 原板件长度,单位:mm。 * 贴皮最终长度,已包含两侧外扩余量,单位:mm。
*/ */
private BigDecimal plateLength; private BigDecimal plateLength;
/** /**
* 原板件宽度,单位:mm。 * 贴皮最终宽度,已包含两侧外扩余量,单位:mm。
*/ */
private BigDecimal plateWidth; private BigDecimal plateWidth;
@@ -98,6 +98,11 @@ public class OrderPlateVeneerDO extends BaseDO {
*/ */
private BigDecimal outerMargin; private BigDecimal outerMargin;
/**
* 贴皮面积,单位:平方米。
*/
private BigDecimal veneerArea;
/** /**
* 贴皮排单ID,0表示未排单。 * 贴皮排单ID,0表示未排单。
*/ */
@@ -38,6 +38,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -51,6 +52,7 @@ import static com.cf.imes.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_PLATE_STATUS_CHANGED; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_PLATE_STATUS_CHANGED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_PLATE_SIZE_INVALID;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_RECORD_INSERT_FAILED; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_RECORD_INSERT_FAILED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SCOPE_REQUIRED; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SCOPE_REQUIRED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SIDE_REQUIRED; import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SIDE_REQUIRED;
@@ -72,6 +74,22 @@ public class VeneerDecomposeServiceImpl implements VeneerDecomposeService {
*/ */
private static final int DECOMPOSE_STAT_BATCH_SIZE = 100; private static final int DECOMPOSE_STAT_BATCH_SIZE = 100;
/**
* 外扩余量需要向板件长、宽的两侧分别增加。
*/
private static final BigDecimal OUTER_MARGIN_DOUBLE = new BigDecimal("2");
/**
* 平方毫米转换为平方米的除数。
*/
private static final BigDecimal SQUARE_MILLIMETER_PER_SQUARE_METER =
new BigDecimal("1000000");
/**
* 单张贴皮面积保留的小数位数。
*/
private static final int VENEER_AREA_SCALE = 3;
@Resource @Resource
private VeneerDecomposeMapper veneerDecomposeMapper; private VeneerDecomposeMapper veneerDecomposeMapper;
@@ -423,6 +441,25 @@ public class VeneerDecomposeServiceImpl implements VeneerDecomposeService {
*/ */
private OrderPlateVeneerDO buildPlateVeneer(PlateDO plate, VeneerDO sourceVeneer, private OrderPlateVeneerDO buildPlateVeneer(PlateDO plate, VeneerDO sourceVeneer,
VeneerSideEnum veneerSide, BigDecimal outerMargin) { VeneerSideEnum veneerSide, BigDecimal outerMargin) {
BigDecimal actualOuterMargin = ObjectUtil.defaultIfNull(outerMargin, BigDecimal.TEN);
BigDecimal sourceLength = plate.getHeight();
BigDecimal sourceWidth = plate.getWidth();
if (sourceLength == null || sourceWidth == null
|| sourceLength.signum() <= 0 || sourceWidth.signum() <= 0
|| actualOuterMargin.signum() < 0) {
throw new ServiceException(VENEER_DECOMPOSE_PLATE_SIZE_INVALID, plate.getPlateNo());
}
// 外扩余量作用于板件四周,长、宽分别增加两倍余量后作为贴皮最终尺寸。
BigDecimal veneerLength = sourceLength.add(
actualOuterMargin.multiply(OUTER_MARGIN_DOUBLE));
BigDecimal veneerWidth = sourceWidth.add(
actualOuterMargin.multiply(OUTER_MARGIN_DOUBLE));
BigDecimal veneerArea = veneerLength.multiply(veneerWidth).divide(
SQUARE_MILLIMETER_PER_SQUARE_METER,
VENEER_AREA_SCALE,
RoundingMode.HALF_UP);
int plateSurface = resolvePlateSurface(plate.getHoleArrange(), veneerSide); int plateSurface = resolvePlateSurface(plate.getHoleArrange(), veneerSide);
return OrderPlateVeneerDO.builder() return OrderPlateVeneerDO.builder()
.organId(plate.getOrganId()) .organId(plate.getOrganId())
@@ -431,14 +468,15 @@ public class VeneerDecomposeServiceImpl implements VeneerDecomposeService {
.orderPlateId(plate.getId()) .orderPlateId(plate.getId())
.plateNo(plate.getPlateNo()) .plateNo(plate.getPlateNo())
.plateName(plate.getName()) .plateName(plate.getName())
.plateLength(plate.getHeight()) .plateLength(veneerLength)
.plateWidth(plate.getWidth()) .plateWidth(veneerWidth)
.plateThickness(plate.getThickness()) .plateThickness(plate.getThickness())
.holeArrange(plate.getHoleArrange()) .holeArrange(plate.getHoleArrange())
.veneerSide(veneerSide.getSide()) .veneerSide(veneerSide.getSide())
.plateSurface(plateSurface) .plateSurface(plateSurface)
.veneerNo(plate.getPlateNo() + veneerSide.getSide()) .veneerNo(plate.getPlateNo() + veneerSide.getSide())
.outerMargin(outerMargin) .outerMargin(actualOuterMargin)
.veneerArea(veneerArea)
.planId(0L) .planId(0L)
.sourceVeneerId(sourceVeneer.getId()) .sourceVeneerId(sourceVeneer.getId())
.sourceVeneerNo(sourceVeneer.getVeneerNo()) .sourceVeneerNo(sourceVeneer.getVeneerNo())
@@ -124,16 +124,6 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
VeneerPlanStatusEnum.NOCUTTING.getStatus(), VeneerPlanStatusEnum.NOCUTTING.getStatus(),
VeneerPlanStatusEnum.OPTIMIZED.getStatus()); VeneerPlanStatusEnum.OPTIMIZED.getStatus());
/**
* 平方毫米转换为平方米的除数。
*/
private static final BigDecimal SQUARE_MILLIMETER_PER_SQUARE_METER = new BigDecimal("1000000");
/**
* 外扩余量需要向长、宽的两侧分别增加。
*/
private static final BigDecimal OUTER_MARGIN_DOUBLE = new BigDecimal("2");
@Resource @Resource
private VeneerPlanMapper veneerPlanMapper; private VeneerPlanMapper veneerPlanMapper;
@@ -877,27 +867,21 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
} }
/** /**
* 根据原板尺寸和外扩余量计算当前贴皮排单的面积。 * 汇总当前贴皮排单的贴皮面积。
* A/B面作为两条贴皮记录分别累计,结果单位为平方米。 * A/B面作为两条贴皮记录分别累计,结果单位为平方米。
* *
* @param veneers 同一贴皮商品编号下的贴皮记录 * @param veneers 同一贴皮商品编号下的贴皮记录
* @return 保留位小数的贴皮总面积 * @return 保留位小数的贴皮总面积
*/ */
private BigDecimal calculateVeneerArea(List<OrderPlateVeneerDO> veneers) { private BigDecimal calculateVeneerArea(List<OrderPlateVeneerDO> veneers) {
BigDecimal totalSquareMillimeter = BigDecimal.ZERO; BigDecimal totalArea = BigDecimal.ZERO;
for (OrderPlateVeneerDO veneer : veneers) { for (OrderPlateVeneerDO veneer : veneers) {
BigDecimal length = veneer.getPlateLength(); BigDecimal veneerArea = veneer.getVeneerArea();
BigDecimal width = veneer.getPlateWidth(); if (veneerArea == null || veneerArea.signum() <= 0) {
BigDecimal outerMargin = Objects.requireNonNullElse(veneer.getOuterMargin(), BigDecimal.ZERO);
if (length == null || width == null || length.signum() <= 0 || width.signum() <= 0
|| outerMargin.signum() < 0) {
throw new ServiceException(VENEER_PLAN_AREA_DATA_INVALID, veneer.getId()); throw new ServiceException(VENEER_PLAN_AREA_DATA_INVALID, veneer.getId());
} }
BigDecimal finalLength = length.add(outerMargin.multiply(OUTER_MARGIN_DOUBLE)); totalArea = totalArea.add(veneerArea);
BigDecimal finalWidth = width.add(outerMargin.multiply(OUTER_MARGIN_DOUBLE));
totalSquareMillimeter = totalSquareMillimeter.add(finalLength.multiply(finalWidth));
} }
return totalSquareMillimeter.divide( return totalArea.setScale(3, RoundingMode.HALF_UP);
SQUARE_MILLIMETER_PER_SQUARE_METER, 4, RoundingMode.HALF_UP);
} }
} }
@@ -384,8 +384,8 @@
og.brand, og.brand,
og.material, og.material,
op.height, op.height,
op.height AS length, opv.plate_length AS length,
op.width, opv.plate_width AS width,
op.thickness, op.thickness,
op.split_width AS splitWidth, op.split_width AS splitWidth,
op.split_height AS splitHeight, op.split_height AS splitHeight,
@@ -116,10 +116,7 @@
<select id="selectPlanStatistics" <select id="selectPlanStatistics"
resultType="com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlanStatisticsDO"> resultType="com.cf.imes.module.executor.dal.dataobject.veneer.VeneerPlanStatisticsDO">
SELECT COUNT(*) AS veneerNum, SELECT COUNT(*) AS veneerNum,
COALESCE(ROUND(SUM( COALESCE(ROUND(SUM(opv.veneer_area), 3), 0) AS veneerArea
(opv.plate_length + opv.outer_margin * 2)
* (opv.plate_width + opv.outer_margin * 2) / 1000000
), 4), 0) AS veneerArea
FROM order_plate_veneer opv FROM order_plate_veneer opv
WHERE opv.deleted = false WHERE opv.deleted = false
AND opv.plan_id = #{planId} AND opv.plan_id = #{planId}
@@ -168,9 +165,7 @@
opv.order_goods_id AS orderGoodsId, opv.order_goods_id AS orderGoodsId,
opv.order_plate_id AS orderPlateId, opv.order_plate_id AS orderPlateId,
opv.plate_no AS plateNo, opv.plate_no AS plateNo,
opv.plate_length AS plateLength, opv.veneer_area AS veneerArea,
opv.plate_width AS plateWidth,
opv.outer_margin AS outerMargin,
opv.source_veneer_id AS sourceVeneerId, opv.source_veneer_id AS sourceVeneerId,
opv.source_veneer_no AS sourceVeneerNo opv.source_veneer_no AS sourceVeneerNo
FROM order_plate_veneer opv FROM order_plate_veneer opv
@@ -74,6 +74,7 @@ veneer.decompose.scope.required=訂單ID列表和板材商品編碼不能同時
veneer.decompose.side.required=A面和B面貼皮至少選擇一個 veneer.decompose.side.required=A面和B面貼皮至少選擇一個
veneer.decompose.plate.status.changed=板件分解狀態已變更,請重新整理後再試 veneer.decompose.plate.status.changed=板件分解狀態已變更,請重新整理後再試
veneer.decompose.record.insert.failed=貼皮分解記錄生成失敗,請重新整理後再試 veneer.decompose.record.insert.failed=貼皮分解記錄生成失敗,請重新整理後再試
veneer.decompose.plate.size.invalid=板件{0}的長寬或外擴餘量異常,無法生成貼皮
veneer.decompose.plate.no.required=板件編號不能為空 veneer.decompose.plate.no.required=板件編號不能為空
veneer.decompose.outer.margin.min=外擴餘量不能小於0 veneer.decompose.outer.margin.min=外擴餘量不能小於0
veneer.reselect.record.required=請選擇需要重選貼皮的資料 veneer.reselect.record.required=請選擇需要重選貼皮的資料
@@ -84,7 +85,7 @@ veneer.remove.record.status.changed=所選貼皮資料已刪除、已排單或
veneer.unplanned.scope.invalid=訂單ID列表和板材商品編碼列表必須且只能傳入一項 veneer.unplanned.scope.invalid=訂單ID列表和板材商品編碼列表必須且只能傳入一項
veneer.plan.record.required=請選擇需要排單的貼皮資料 veneer.plan.record.required=請選擇需要排單的貼皮資料
veneer.plan.record.status.changed=所選貼皮資料已排單、已刪除或狀態發生變化,請重新整理後再試 veneer.plan.record.status.changed=所選貼皮資料已排單、已刪除或狀態發生變化,請重新整理後再試
veneer.plan.area.data.invalid=貼皮記錄{0}的板件尺寸或外擴餘量異常,無法計算貼皮面積 veneer.plan.area.data.invalid=貼皮記錄{0}的面積資料異常,無法建立貼皮排單
veneer.plan.create.failed=貼皮排單建立失敗,請稍後再試 veneer.plan.create.failed=貼皮排單建立失敗,請稍後再試
veneer.plan.group.required=請提交需要建立的貼皮排單分組 veneer.plan.group.required=請提交需要建立的貼皮排單分組
veneer.plan.group.source.no.required=貼皮排單分組的貼皮商品編號不能為空 veneer.plan.group.source.no.required=貼皮排單分組的貼皮商品編號不能為空
@@ -74,6 +74,7 @@ veneer.decompose.scope.required=Order ID list and goods code cannot both be empt
veneer.decompose.side.required=At least one veneer must be selected for side A or B veneer.decompose.side.required=At least one veneer must be selected for side A or B
veneer.decompose.plate.status.changed=Plate decomposition status has changed. Please refresh and retry veneer.decompose.plate.status.changed=Plate decomposition status has changed. Please refresh and retry
veneer.decompose.record.insert.failed=Failed to create veneer decomposition records. Please refresh and retry veneer.decompose.record.insert.failed=Failed to create veneer decomposition records. Please refresh and retry
veneer.decompose.plate.size.invalid=Plate {0} has invalid dimensions or outer margin and cannot generate veneer
veneer.decompose.plate.no.required=Plate numbers cannot be empty veneer.decompose.plate.no.required=Plate numbers cannot be empty
veneer.decompose.outer.margin.min=Outer margin cannot be less than 0 veneer.decompose.outer.margin.min=Outer margin cannot be less than 0
veneer.reselect.record.required=Please select records for veneer reselection veneer.reselect.record.required=Please select records for veneer reselection
@@ -84,7 +85,7 @@ veneer.remove.record.status.changed=The selected veneer data has been removed, s
veneer.unplanned.scope.invalid=Exactly one of the order ID list and goods code list must be provided veneer.unplanned.scope.invalid=Exactly one of the order ID list and goods code list must be provided
veneer.plan.record.required=Please select veneer records to schedule veneer.plan.record.required=Please select veneer records to schedule
veneer.plan.record.status.changed=The selected veneer data has been scheduled, removed, or changed. Please refresh and retry veneer.plan.record.status.changed=The selected veneer data has been scheduled, removed, or changed. Please refresh and retry
veneer.plan.area.data.invalid=Veneer record {0} has invalid plate dimensions or outer margin veneer.plan.area.data.invalid=Veneer record {0} has invalid area data and cannot create a veneer plan
veneer.plan.create.failed=Failed to create the veneer plan. Please retry later veneer.plan.create.failed=Failed to create the veneer plan. Please retry later
veneer.plan.group.required=Please submit at least one veneer plan group veneer.plan.group.required=Please submit at least one veneer plan group
veneer.plan.group.source.no.required=The veneer product number of a plan group is required veneer.plan.group.source.no.required=The veneer product number of a plan group is required
@@ -74,6 +74,7 @@ veneer.decompose.scope.required=订单ID列表和板材商品编码不能同时
veneer.decompose.side.required=A面和B面贴皮至少选择一个 veneer.decompose.side.required=A面和B面贴皮至少选择一个
veneer.decompose.plate.status.changed=板件分解状态已变更,请刷新后重试 veneer.decompose.plate.status.changed=板件分解状态已变更,请刷新后重试
veneer.decompose.record.insert.failed=贴皮分解记录生成失败,请刷新后重试 veneer.decompose.record.insert.failed=贴皮分解记录生成失败,请刷新后重试
veneer.decompose.plate.size.invalid=板件{0}的长宽或外扩余量异常,无法生成贴皮
veneer.decompose.plate.no.required=板件编号不能为空 veneer.decompose.plate.no.required=板件编号不能为空
veneer.decompose.outer.margin.min=外扩余量不能小于0 veneer.decompose.outer.margin.min=外扩余量不能小于0
veneer.reselect.record.required=请选择需要重选贴皮的数据 veneer.reselect.record.required=请选择需要重选贴皮的数据
@@ -84,7 +85,7 @@ veneer.remove.record.status.changed=所选贴皮数据已删除、已排单或
veneer.unplanned.scope.invalid=订单ID列表和板材商品编码列表必须且只能传入一项 veneer.unplanned.scope.invalid=订单ID列表和板材商品编码列表必须且只能传入一项
veneer.plan.record.required=请选择需要排单的贴皮数据 veneer.plan.record.required=请选择需要排单的贴皮数据
veneer.plan.record.status.changed=所选贴皮数据已排单、已删除或状态发生变化,请刷新后重试 veneer.plan.record.status.changed=所选贴皮数据已排单、已删除或状态发生变化,请刷新后重试
veneer.plan.area.data.invalid=贴皮记录{0}的板件尺寸或外扩余量异常,无法计算贴皮面积 veneer.plan.area.data.invalid=贴皮记录{0}的面积数据异常,无法创建贴皮排单
veneer.plan.create.failed=贴皮排单创建失败,请稍后重试 veneer.plan.create.failed=贴皮排单创建失败,请稍后重试
veneer.plan.group.required=请提交需要创建的贴皮排单分组 veneer.plan.group.required=请提交需要创建的贴皮排单分组
veneer.plan.group.source.no.required=贴皮排单分组的贴皮商品编号不能为空 veneer.plan.group.source.no.required=贴皮排单分组的贴皮商品编号不能为空