diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/ReturnToWarehouseDto.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/ReturnToWarehouseDto.java new file mode 100644 index 000000000..71489fbd7 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/ReturnToWarehouseDto.java @@ -0,0 +1,21 @@ +package org.springblade.desk.logistics.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +@Schema(description = "出库操作") +public class ReturnToWarehouseDto { + + //箱条码 + @NotBlank(message = "箱条码不能为空") + private String boxBarcode; + //站点id + @NotBlank(message = "站点编号不能为空") + private String stationCode; + //终点id + private Long endLocationId ; + //终点名称 + private String endName; +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java index 892bdadc1..c0f14fe2c 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java @@ -46,6 +46,10 @@ public class Station extends BaseEntity { * 放货输送线 站点类型常量 */ public static final String DROPOFF_CONVEYOR_LINE = "1001"; + /** + * 放货输送线 站点类型常量 + */ + public static final String DROPOFF_CONVEYOR_LINE_NAME = "输送线终点"; /** diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/vo/BsWorkCenterVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/vo/BsWorkCenterVO.java new file mode 100644 index 000000000..51ff66ac3 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/vo/BsWorkCenterVO.java @@ -0,0 +1,12 @@ +package org.springblade.desk.logistics.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "wslist返回对象") +public class BsWorkCenterVO { + private Long id; + private String wcName; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/OemStatementEntity.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/OemStatementEntity.java index feeb67d8e..8de2373df 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/OemStatementEntity.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/OemStatementEntity.java @@ -29,27 +29,27 @@ public class OemStatementEntity extends BaseEntity { private static final long serialVersionUID = 1L; /** - * 未结算 + * 无需结算 */ - public static Short NOT_NEED_SETTLEMENT = -1; + public static Integer NOT_NEED_SETTLEMENT = -1; /** * 未结算 */ - public static Short NO_SETTLEMENT = 1; + public static Integer NO_SETTLEMENT = 1; /** * 结算中 */ - public static Short IN_SETTLEMENT = 2; + public static Integer IN_SETTLEMENT = 2; /** * 结算异常 */ - public static Short ERR_SETTLEMENT = 3; + public static Integer ERR_SETTLEMENT = 3; /** * 已结算 */ - public static Short OK_SETTLEMENT = 4; + public static Integer OK_SETTLEMENT = 4; - public static Map rosStatusMap = new HashMap<>(8); + public static Map rosStatusMap = new HashMap<>(8); static { rosStatusMap.put(NOT_NEED_SETTLEMENT, "无需结算"); @@ -95,4 +95,14 @@ public class OemStatementEntity extends BaseEntity { @Schema(description = "状态") private Integer rosStatus; + public String getRosStatusName() { + return rosStatusMap.get(rosStatus); + } + + /** + * 备注 + */ + @Schema(description = "备注") + private String memo; + } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/PlatingTypeRulesEntity.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/PlatingTypeRulesEntity.java new file mode 100644 index 000000000..409e79431 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/PlatingTypeRulesEntity.java @@ -0,0 +1,42 @@ +package org.springblade.desk.oem.pojo.entity; + +import lombok.Data; +import io.swagger.v3.oas.annotations.media.Schema; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.math.BigDecimal; +import java.util.Date; + +import lombok.EqualsAndHashCode; +import org.springblade.core.mp.base.BaseEntity; +import org.springblade.core.tenant.mp.TenantEntity; + +import java.io.Serial; + +/** + * 外协镀种规则 实体类 + * + * @author qyl + * @since 2026-03-03 + */ +@Data +@TableName("MES_PLATING_TYPE_RULES") +@Schema(description = "PlatingTypeRules对象") +@EqualsAndHashCode(callSuper = true) +public class PlatingTypeRulesEntity extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 订单镀种 + */ + @Schema(description = "订单镀种") + private String orderPlat; + /** + * 报价单镀种 + */ + @Schema(description = "报价单镀种") + private String quotationPlat; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesExcel.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesExcel.java new file mode 100644 index 000000000..f7bdd5aeb --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesExcel.java @@ -0,0 +1,45 @@ +package org.springblade.desk.oem.pojo.excel; + + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; + +import java.io.Serializable; +import java.io.Serial; + + +/** + * 外协镀种规则 Excel实体类 + * + * @author qyl + * @since 2026-03-03 + */ +@Data +@ColumnWidth(25) +@HeadRowHeight(20) +@ContentRowHeight(18) +public class PlatingTypeRulesExcel implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + /** + * 订单镀种 + */ + @ColumnWidth(20) + @ExcelProperty("订单镀种") + private String orderPlat; + /** + * 报价单镀种 + */ + @ColumnWidth(20) + @ExcelProperty("报价单镀种") + private String quotationPlat; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesImport.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesImport.java new file mode 100644 index 000000000..110da7ce0 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesImport.java @@ -0,0 +1,29 @@ +package org.springblade.desk.oem.pojo.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.mp.base.BaseEntity; + +/** + * 外协镀种规则导入 + * + * @author qyl + * @since 2026年3月3日 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PlatingTypeRulesImport extends BaseEntity { + + /** + * 订单镀种 + */ + @ExcelProperty(index = 0) + private String orderPlat; + /** + * 报价单镀种 + */ + @ExcelProperty(index = 1) + private String quotationPlat; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemApprovalQuery.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemApprovalQuery.java index 129654e00..ca4bb63d7 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemApprovalQuery.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemApprovalQuery.java @@ -22,7 +22,7 @@ public class OemApprovalQuery { * 车间订单号 */ @Schema(description = "车间订单号") - private String orderCode; + private String woCode; /** * 零件号 */ diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemSettleAccountsSave.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemSettleAccountsSave.java new file mode 100644 index 000000000..f9e36d9d2 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemSettleAccountsSave.java @@ -0,0 +1,30 @@ +package org.springblade.desk.oem.pojo.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springblade.desk.oem.pojo.vo.StatementVO; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +/** + * 外协结算入参 + */ +@Data +public class OemSettleAccountsSave { + + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "镀后入库时间") + @NotNull(message = "镀后入库时间不能为空") + private LocalDate putStoreDate; + + @Schema(description = "现执行价格") + private BigDecimal price; + + @Schema(description = "外协结算单集合") + @NotNull(message = "外协结算单集合不能为空") + List statementList; +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/PriceSheetQuery.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/PriceSheetQuery.java index c2c09cd43..c119b600a 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/PriceSheetQuery.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/PriceSheetQuery.java @@ -17,6 +17,11 @@ public class PriceSheetQuery { */ @Schema(description = "外协厂商CODE") private String ocCode; + /** + * 外协厂商名称 + */ + @Schema(description = "外协厂商名称") + private String ocName; /** * 零件号 */ diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/StatementQuery.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/StatementQuery.java index cb3b48bba..074bc04eb 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/StatementQuery.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/StatementQuery.java @@ -1,6 +1,7 @@ package org.springblade.desk.oem.pojo.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -62,6 +63,7 @@ public class StatementQuery { /** * 结算单状态 */ - @Schema(description = "结算单状态(传字符串1,2,3,4)") + @Schema(description = "结算单状态(传字符串1,2,3,4)-1无需结算,1未结算,2结算中,3结算异常,4已结算") + @NotNull(message = "结算单状态不能为空") private String rosStatusList; } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemApprovalVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemApprovalVO.java index e0d2c1296..056c209bb 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemApprovalVO.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemApprovalVO.java @@ -4,11 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import org.springblade.desk.produce.pojo.entity.WorkOrderRun; -import org.springblade.desk.produce.pojo.enums.WorkOrderRunStatusEnum; import java.io.Serial; -import java.time.LocalDateTime; -import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** * 外协审批 视图实体类 @@ -22,7 +21,30 @@ import java.util.Date; public class OemApprovalVO extends WorkOrderRun { @Serial private static final long serialVersionUID = 1L; + /** + * 1:正常 + */ + public static Integer APPROVAL_STATUS_NORMAL = 1; + /** + * 2:审批中 + */ + public static Integer APPROVAL_STATUS_UNDER = 2; + /** + * 3:不通过 + */ + public static Integer APPROVAL_STATUS_FAIL = 3; + /** + * 4:通过 + */ + public static Integer APPROVAL_STATUS_VIA = 4; + public static Map approvalStatusMap = new HashMap(4); + static { + approvalStatusMap.put(APPROVAL_STATUS_NORMAL, "正常"); + approvalStatusMap.put(APPROVAL_STATUS_UNDER, "审批中"); + approvalStatusMap.put(APPROVAL_STATUS_FAIL, "审批不通过"); + approvalStatusMap.put(APPROVAL_STATUS_VIA, "审批通过"); + } @Schema(description = "车间订单ID") private Long woId; @@ -50,7 +72,7 @@ public class OemApprovalVO extends WorkOrderRun { private Long makeQty; @Schema(description = "面积(dm²)") - private String totalArea; + private String area; // @Schema(description = "建立时间") // private Date createDate; @@ -60,4 +82,15 @@ public class OemApprovalVO extends WorkOrderRun { @Schema(description = "审批人") private String approver; + + @Schema(description = "审批状态;1:正常,2:审批中,3:不通过,4:通过") + private Integer approvalStatus; + + @Schema(description = "审批状态名称") + private String approvalName; + + public String getApprovalName() { + return approvalStatusMap.get(approvalStatus); + } + } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemOrderVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemOrderVO.java index 6eb7f817b..907e92ced 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemOrderVO.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemOrderVO.java @@ -5,6 +5,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.springblade.desk.order.pojo.enums.YieldOrderEnum; import org.springblade.desk.produce.pojo.entity.WorkOrderRun; +import org.springblade.desk.produce.pojo.enums.WorkOrderEnum; import org.springblade.desk.produce.pojo.enums.WorkOrderRunStatusEnum; import java.io.Serial; @@ -41,7 +42,7 @@ public class OemOrderVO extends WorkOrderRun { @Schema(description = "运行订单状态(运行状态;1.正常,2.已下达,3.加工中,4.检验中,13.审理中,14.返工中,15.已完工,21已作废)") public String getRunStatusName() { - return WorkOrderRunStatusEnum.getName(this.getRunStatus().intValue()); + return WorkOrderEnum.getName(this.getWorkOrderStatus().intValue()); } @Schema(description = "批次号") @@ -107,4 +108,7 @@ public class OemOrderVO extends WorkOrderRun { @Schema(description = "外协订单分类(车间单号为WX:外协订单,车间单号为WO:协作订单)") private String oemOrderType; + + @Schema(description = "审批状态;1:正常,2:审批中,3:不通过,4:通过") + private Integer approvalStatus; } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemProcessVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemProcessVO.java index 496eaecca..22f635b87 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemProcessVO.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemProcessVO.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serial; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; /** * 外协工序 视图实体类 @@ -24,4 +26,11 @@ public class OemProcessVO extends OemProcessEntity { @Schema(description = "工艺能力名称集合") private String caNames; + + @Schema(description = "工序IDStr,前端用") + private String processIdStr; + + public String getProcessIdStr() { + return this.getProcessId().toString(); + } } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/PlatingTypeRulesVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/PlatingTypeRulesVO.java new file mode 100644 index 000000000..382cd2745 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/PlatingTypeRulesVO.java @@ -0,0 +1,21 @@ +package org.springblade.desk.oem.pojo.vo; + +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 外协镀种规则 视图实体类 + * + * @author qyl + * @since 2026-03-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PlatingTypeRulesVO extends PlatingTypeRulesEntity { + @Serial + private static final long serialVersionUID = 1L; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/StatementVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/StatementVO.java index 7c81ce4cd..93a3ebf86 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/StatementVO.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/StatementVO.java @@ -2,15 +2,16 @@ package org.springblade.desk.oem.pojo.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.springblade.desk.oem.pojo.entity.OemStatementEntity; + +import java.util.List; /** * 外协订单结算VO */ @Data -public class StatementVO { +public class StatementVO extends OemStatementEntity { - @Schema(description = "车间作业计划ID") - private Long wpId; @Schema(description = "车间订单ID") private Long woId; @@ -48,13 +49,19 @@ public class StatementVO { @Schema(description = "零件名称") private String partName; + @Schema(description = "镀层物料") + private String plateGoodsCode; + @Schema(description = "批次号") private String batchNo; @Schema(description = "生产标识") private String prodIdent; - @Schema(description = "工序") + @Schema(description = "工序编码") + private String psCode; + + @Schema(description = "工序名称") private String psName; @Schema(description = "工艺能力") @@ -75,6 +82,9 @@ public class StatementVO { @Schema(description = "外协厂商") private String ocCode; + @Schema(description = "外协厂商名称") + private String ocName; + @Schema(description = "镀种") private String plate; @@ -90,16 +100,8 @@ public class StatementVO { @Schema(description = "涂箭个数") private String tjtNum; - @Schema(description = "结算单价") - private String unitPrice; - - @Schema(description = "计量单位") - private String unit; - - @Schema(description = "结算金额") - private String totalPrice; - - @Schema(description = "报价单号") - private String quotation; - + /** + * 同外协厂家下有效期内的全部该工序报价 + */ + private List priceSheetList; } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/vo/ProduceMonitorDsPartVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/vo/ProduceMonitorDsPartVO.java index 54c194215..05a917399 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/vo/ProduceMonitorDsPartVO.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/vo/ProduceMonitorDsPartVO.java @@ -54,4 +54,7 @@ public class ProduceMonitorDsPartVO { @Schema(description = "是否印字:1、否,2、单,3、双") private String isPrint; + @Schema(description = "pdm零件图纸地址") + private String url; + } diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/util/PriceMatcher.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/util/PriceMatcher.java new file mode 100644 index 000000000..6a5de8b5b --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/util/PriceMatcher.java @@ -0,0 +1,100 @@ +package org.springblade.desk.util; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 价格处理 + */ +public class PriceMatcher { + + /** + * 查找包含指定价格的备注 + * + * @param remarks 备注列表 + * @param targetPrice 目标价格 + * @return 匹配的备注列表 + */ + public static List findRemarksByPrice(List remarks, BigDecimal targetPrice) { + if (remarks == null || targetPrice == null) { + return new ArrayList<>(); + } + + List matchedRemarks = new ArrayList<>(); + + for (String remark : remarks) { + if (remark == null || remark.trim().isEmpty()) { + continue; + } + + if (containsPrice(remark, targetPrice)) { + matchedRemarks.add(remark); + } + } + + return matchedRemarks; + } + + /** + * 判断备注是否包含目标价格 + */ + private static boolean containsPrice(String remark, BigDecimal targetPrice) { + // 正则表达式匹配价格范围或单价 + // 匹配如:350.01-360、467.5、100.5-200.8 + String regex = "(\\d+(?:\\.\\d+)?)(?:-(\\d+(?:\\.\\d+)?))?"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(remark); + + while (matcher.find()) { + String startPriceStr = matcher.group(1); + String endPriceStr = matcher.group(2); + + try { + if (endPriceStr != null) { + // 价格范围,如 "350.01-360" + BigDecimal startPrice = new BigDecimal(startPriceStr); + BigDecimal endPrice = new BigDecimal(endPriceStr); + + // 检查目标价格是否在范围内 + if (targetPrice.compareTo(startPrice) >= 0 && + targetPrice.compareTo(endPrice) <= 0) { + return true; + } + } else { + // 单一价格,如 "467.5" + BigDecimal singlePrice = new BigDecimal(startPriceStr); + + // 检查目标价格是否等于这个价格 + if (targetPrice.compareTo(singlePrice) == 0) { + return true; + } + } + } catch (NumberFormatException e) { + // 解析失败,跳过这个匹配 + continue; + } + } + + return false; + } + + /** + * 使用Stream API的版本 + */ + public static Set findRemarksByPriceStream(Set remarks, BigDecimal targetPrice) { + if (remarks == null || targetPrice == null) { + return new HashSet<>(); + } + + return remarks.stream() + .filter(remark -> remark != null && !remark.trim().isEmpty()) + .filter(remark -> containsPrice(remark, targetPrice)) + .collect(Collectors.toSet()); + } +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.java index bb8370cae..bfd8c50f0 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.java @@ -63,4 +63,11 @@ public interface BsWorkCenterMapper extends BaseMapper { List getList(); BsWorkCenterEntity selectBsWorkCenterByWcCode(@Param("wcCode")String wcCode); + + /** + * 根据ID集合查询工作中心 + * @param ids ID集合 + * @return 工作中心列表 + */ + List selectByIds(@Param("ids") List ids); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.xml new file mode 100644 index 000000000..6021cbd9f --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/IBsWorkCenterService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/IBsWorkCenterService.java index cf1dd8ac3..2226e0343 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/IBsWorkCenterService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/IBsWorkCenterService.java @@ -70,4 +70,6 @@ public interface IBsWorkCenterService extends BaseService { * @return */ BsWorkCenterEntity selectBsWorkCenterByWcCode(String wcCode); + + List getByIds(List list); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/BsWorkCenterServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/BsWorkCenterServiceImpl.java index 1379628e9..0051f33cd 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/BsWorkCenterServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/BsWorkCenterServiceImpl.java @@ -74,4 +74,9 @@ public class BsWorkCenterServiceImpl extends BaseServiceImpl getByIds(List list) { + return workCenterMapper.selectByIds(list); + } + } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java index 37acc7330..867276245 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; +import jodd.util.StringUtil; import lombok.AllArgsConstructor; import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.mp.support.Condition; @@ -18,6 +19,7 @@ import org.springblade.desk.dashboard.service.IBsWorkCenterService; import org.springblade.desk.device.pojo.entity.EquipmentEntity; import org.springblade.desk.device.pojo.vo.EquipmentVO; import org.springblade.desk.logistics.pojo.dto.BoxBindingDto; +import org.springblade.desk.logistics.pojo.dto.ReturnToWarehouseDto; import org.springblade.desk.logistics.pojo.dto.TaskDto; import org.springblade.desk.logistics.pojo.vo.TaskVO; import org.springblade.desk.logistics.service.IOrderBoxService; @@ -110,5 +112,24 @@ public class OrderBoxController extends BladeController { IPage pages = taskService.selectPage(Condition.getPage(query), taskDto); return R.data(pages); } + + /** + * 回库 + */ + @PostMapping("/return-warehouse") + @ApiOperationSupport(order = 5) + @Operation(summary = "回库", description = "调用回库") + public R inventoryReturnToWarehouse(@RequestParam ReturnToWarehouseDto returnToWarehouseDto){ + return iOrderBoxService.inventoryReturnToWarehouse(returnToWarehouseDto); + } + /** + * 回调作业中心list + */ + @PostMapping("/return-warehouse-list") + @ApiOperationSupport(order = 6) + @Operation(summary = "回调作业中心list", description = "回调作业中心list") + public R inventoryReturnToWarehouseList(){ + return iOrderBoxService.returnToWarehouseList(); + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java index 4af6129e6..de6e29754 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java @@ -2,6 +2,7 @@ package org.springblade.desk.logistics.service; import org.springblade.core.tool.api.R; import org.springblade.desk.logistics.pojo.dto.BoxBindingDto; +import org.springblade.desk.logistics.pojo.dto.ReturnToWarehouseDto; import java.math.BigDecimal; @@ -37,15 +38,15 @@ public interface IOrderBoxService { */ R boxBinding(BoxBindingDto boxBinding); + /** - * 箱条码与订单解绑 - * 功能:解除指定箱条码对应的所有订单绑定关系,支持箱的重新绑定或回收 - * - * @param boxBarcode 箱条码,唯一标识需要解绑的箱子 - * @return R 通用返回结果 - * - 成功:R.success(),携带解绑成功的提示或解绑的订单数量 - * - 失败:R.fail(),携带失败原因(如箱条码不存在、解绑数据异常等) + * 释放站点并调用AGV小车接口(优化后的核心方法) + * 业务场景:任务结束后释放站点,触发AGV小车相关操作 + * @param ReturnToWarehouseDto returnToWarehouseDto + * @return 统一返回结果 */ - R boxOrderUnbind(String boxBarcode); + R inventoryReturnToWarehouse(ReturnToWarehouseDto returnToWarehouseDto); + + R returnToWarehouseList(); } \ No newline at end of file diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IPipelineOrderBoxService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IPipelineOrderBoxService.java new file mode 100644 index 000000000..20f8fa2e7 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IPipelineOrderBoxService.java @@ -0,0 +1,18 @@ +package org.springblade.desk.logistics.service; + +import org.springblade.core.tool.api.R; +import org.springblade.desk.logistics.pojo.entity.Task; + +public interface IPipelineOrderBoxService { + /** + * 箱条码与订单解绑 + * 功能:解除指定箱条码对应的所有订单绑定关系,支持箱的重新绑定或回收 + * + * @param boxBarcode 箱条码,唯一标识需要解绑的箱子 + * @return R 通用返回结果 + * - 成功:R.success(),携带解绑成功的提示或解绑的订单数量 + * - 失败:R.fail(),携带失败原因(如箱条码不存在、解绑数据异常等) + */ + R boxOrderUnbind(String boxBarcode); + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java index 0abe20fc7..b98a23a15 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java @@ -2,23 +2,32 @@ package org.springblade.desk.logistics.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import groovy.lang.Lazy; import lombok.extern.slf4j.Slf4j; import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tool.api.R; +import org.springblade.desk.dashboard.service.IBsWorkCenterService; import org.springblade.desk.logistics.pojo.dto.BoxBindingDto; +import org.springblade.desk.logistics.pojo.dto.ReturnToWarehouseDto; import org.springblade.desk.logistics.pojo.entity.*; +import org.springblade.desk.logistics.pojo.vo.BsWorkCenterVO; import org.springblade.desk.logistics.service.*; +import org.springblade.desk.logistics.utils.AgvTaskTypeUtil; import org.springblade.desk.order.pojo.entity.YieldOrder; import org.springblade.desk.order.service.IYieldOrderService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; +import static org.springblade.desk.logistics.constant.AgvConstant.EQUIPMENT_TYPE_AGV; import static org.springblade.desk.logistics.pojo.entity.OrderBind.STATUS_UNBINDED; -import static org.springblade.desk.logistics.pojo.entity.Station.STATUS_OCCUPIED; +import static org.springblade.desk.logistics.pojo.entity.Station.*; +import static org.springblade.desk.logistics.utils.CollectionCheckUtil.isFieldInCollection; /** * 订单箱业务实现类 @@ -51,6 +60,11 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { */ private final ILocationService iLocationService; + + private final AgvTaskTypeUtil agvTaskTypeUtil; + private final IBsWorkCenterService bsWorkCenterService; + private final IPipelineService iPipelineOrderBoxService; + /** * 任务运行中状态集合:包含任务从启动到待入库的所有中间状态 * 用于判断箱条码是否存在未完成的运行任务 @@ -69,36 +83,41 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { RUNNING_STATUSES.add(Task.STATUS_BACK_TO_STORAGE);// 返库状态 } - /** - * 构造器注入依赖服务(替代@Autowired,符合Spring最佳实践) - * - * @param iYieldOrderService 工单服务 - * @param iTaskService 任务服务 - * @param iOrderBindService 订单绑定服务 - * @param iStationService 站点服务 - * @param iLocationService 库位服务 - */ - public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService) { + public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService, AgvTaskTypeUtil agvTaskTypeUtil, IBsWorkCenterService bsWorkCenterService, IPipelineService iPipelineOrderBoxService) { this.iYieldOrderService = iYieldOrderService; this.iTaskService = iTaskService; this.iOrderBindService = iOrderBindService; this.iStationService = iStationService; this.iLocationService = iLocationService; + this.agvTaskTypeUtil = agvTaskTypeUtil; + this.bsWorkCenterService = bsWorkCenterService; + this.iPipelineOrderBoxService = iPipelineOrderBoxService; } + /** + * 构造器注入依赖服务(替代@Autowired,符合Spring最佳实践) + * + * @param iYieldOrderService 工单服务 + * @param iTaskService 任务服务 + * @param iOrderBindService 订单绑定服务 + * @param iStationService 站点服务 + * @param iLocationService 库位服务 + */ + + /** * 维护订单配件实际重量 * 功能:根据流程卡号更新对应工单的实际称重数据 * - * @param cardNo 流程卡号(唯一标识工单) + * @param cardNo 流程卡号(唯一标识工单) * @param actualWeight 实际称重值(单位:业务约定,如千克) * @return R 操作结果 - * - 成功:R.success() - * - 失败:R.fail(),携带具体失败原因 + * - 成功:R.success() + * - 失败:R.fail(),携带具体失败原因 */ @Override public R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight) { - log.info("接收到实际重量:{},对应的流程卡号:{}",actualWeight,cardNo); + log.info("接收到实际重量:{},对应的流程卡号:{}", actualWeight, cardNo); // 根据流程卡号查询工单(按更新时间倒序,取最新记录) List list = iYieldOrderService.list(new QueryWrapper().eq("CARD_NO", cardNo).orderByDesc("UPDATE_TIME")); @@ -106,7 +125,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { list.get(0).setActualWeighing(actualWeight); // 执行更新并返回结果 - return iYieldOrderService.updateById(list.get(0))? R.success():R.fail("实际称重维护:卡号维护失败"); + return iYieldOrderService.updateById(list.get(0)) ? R.success() : R.fail("实际称重维护:卡号维护失败"); } /** @@ -115,8 +134,8 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { * * @param boxBinding 箱绑定参数(包含箱条码、订单ID列表、工位ID等) * @return R 绑定结果 - * - 成功:R.success() - * - 失败:R.fail(),携带具体失败原因(如参数为空、订单已绑定、重量超限等) + * - 成功:R.success() + * - 失败:R.fail(),携带具体失败原因(如参数为空、订单已绑定、重量超限等) */ @Override public R boxBinding(BoxBindingDto boxBinding) { @@ -154,7 +173,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { } // 6. 完善任务信息并保存 - task= (Task) location.getData(); + task = (Task) location.getData(); task.setTaskStatus(Task.STATUS_START); // 设置任务初始状态为启动 task.setCreateTime(new Date()); // 设置任务创建时间 task.setCreateUser(AuthUtil.getUserId()); @@ -162,7 +181,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { boolean orderBool = boxBinding.getOrderIdList() == null || boxBinding.getOrderIdList().size() == 0; if (orderBool) { task.setWeight(new BigDecimal(0)); - }else { + } else { task.setWeight(getWeightByOrderIdList(boxBinding.getOrderIdList())); } // 8. 重量校验(小于50kg才允许绑定,避免超重) @@ -178,75 +197,245 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { // 10. 无订单则直接返回成功,有订单则执行订单绑定 if (orderBool) { return R.success(); - }else { - return saveOrderBindingList(task.getId(),boxBinding.getOrderIdList()); + } else { + return saveOrderBindingList(task.getId(), boxBinding.getOrderIdList()); } } + /** - * 箱条码与订单解绑 - * 流程:参数校验 → 查询运行中任务 → 重置站点/库位状态 → 解绑订单 → 结束任务 + * 释放站点并调用AGV小车接口 + *

+ * 业务场景:任务结束后释放指定站点,根据终点类型触发不同的AGV小车调度逻辑 + * 核心流程: + * 1. 校验入参和基础数据(站点、任务、终点信息) + * 2. 分两种场景处理AGV调度: + * - 场景1:仅指定终点名称(下料输送线)→ 直接调度AGV到下料线 + * - 场景2:指定终点站点ID → 调度AGV到目标空闲站点 + * 3. AGV调用失败时自动回滚站点状态,保证数据一致性 * - * @param boxBarcode 箱条码 - * @return R 解绑结果 - * - 成功:R.success() - * - 失败:R.fail(),携带具体失败原因(如箱条码为空) + * @param returnToWarehouseDto 回库请求参数DTO + * @return 统一返回结果 + * @throws IllegalArgumentException 入参无效、基础数据不存在时抛出 */ @Override - public R boxOrderUnbind(String boxBarcode) { - // 1. 参数非空校验 - if (boxBarcode.isEmpty()) { - log.warn("箱绑定参数为空或箱条码缺失"); - return R.fail("箱条码不能为空"); + public R inventoryReturnToWarehouse(ReturnToWarehouseDto returnToWarehouseDto) { + // ========== 1. 入参和基础数据校验(前置校验,提前失败) ========== + // 校验DTO非空 + Assert.notNull(returnToWarehouseDto, "回库请求参数不能为空"); + String stationCode = returnToWarehouseDto.getStationCode(); + Assert.hasText(stationCode, "站点编号不能为空"); + + // 查询站点信息(封装为方法,提升可读性) + Station targetStation = getStationByCode(stationCode); + // 查询有效任务列表 + List validTaskList = getValidTaskList(stationCode); + // 校验站点状态 + checkStationStatus(targetStation); + // 校验终点信息 + checkEndLocationInfo(returnToWarehouseDto); + + // ========== 2. 分场景处理AGV调度 ========== + try { + if (isDropoffConveyorLineScenario(returnToWarehouseDto)) { + // 场景1:仅指定下料输送线名称 → 调度AGV到下料线 + return handleDropoffConveyorLineScenario(targetStation, validTaskList); + } else { + // 场景2:指定终点站点ID → 调度AGV到目标站点 + return handleTargetStationScenario(targetStation, returnToWarehouseDto, validTaskList); + } + } catch (Exception e) { + log.error("库存回库-AGV调度异常,站点编号:{}", stationCode, e); + return R.fail("库存回库操作失败:" + e.getMessage()); } + } - // 2. 查询该箱条码对应的运行中任务 - List taskList = iTaskService.list( - new LambdaQueryWrapper().eq(Task::getBoxBarcode, boxBarcode).in(false,Task::getTaskStatus,RUNNING_STATUSES) - ); + /** + * 根据站点编号查询站点信息(不存在则抛异常) + */ + private Station getStationByCode(String stationCode) { + LambdaQueryWrapper stationQuery = new LambdaQueryWrapper() + .eq(Station::getStationCode, stationCode); + List stationList = iStationService.list(stationQuery); + + if (stationList == null || stationList.isEmpty()) { + log.warn("站点编号不存在,入参:{}", stationCode); + throw new IllegalArgumentException("输入站点编号不存在"); + } + return stationList.get(0); + } - // 3. 遍历任务,重置站点/库位状态 + 解绑订单 + 结束任务 - for (Task task : taskList) { - // 3.1 重置站点状态为占用(释放站点) - if (task.getStationId()!=null&&task.getStationId()!=0) { - Station station = iStationService.getById(task.getStationId()); - station.setStationStatus(STATUS_OCCUPIED); - iStationService.updateById(station); - } + /** + * 查询有效任务列表(运行中状态,不存在则抛异常) + */ + private List getValidTaskList(String stationCode) { + LambdaQueryWrapper taskQuery = new LambdaQueryWrapper() + .eq(Task::getBoxBarcode, stationCode) + .in(Task::getTaskStatus, RUNNING_STATUSES); // RUNNING_STATUSES建议抽取为常量 + List taskList = iTaskService.list(taskQuery); + + if (taskList == null || taskList.isEmpty()) { + log.warn("箱条码数据异常,站点编号:{}", stationCode); + throw new IllegalArgumentException("箱条码数据异常"); + } + return taskList; + } - // 3.2 重置库位状态为占用(释放库位) - if (task.getLocationId()!=null&&task.getLocationId()!=0) { - Location location = iLocationService.getById(task.getLocationId()); - location.setLocationStatus(STATUS_OCCUPIED); - iLocationService.updateById(location); + /** + * 校验站点状态(必须为空闲) + */ + private void checkStationStatus(Station station) { + if (!STATUS_FREE.equals(station.getStationStatus())) { + log.warn("站点被占用,站点编号:{},当前状态:{}", station.getStationCode(), station.getStationStatus()); + throw new IllegalArgumentException("该站点正在被使用,请使用其他站点"); + } + } + + /** + * 校验终点信息(终点ID/名称不能为空) + */ + private void checkEndLocationInfo(ReturnToWarehouseDto dto) { + Long endLocationId = dto.getEndLocationId(); + String endName = dto.getEndName(); + + // 终点ID和名称都为空 → 异常 + if ((endLocationId == null || endLocationId == 0) && (endName == null || endName.isBlank())) { + throw new IllegalArgumentException("请检查运送线终点,运送线终点为空"); + } + + // 仅终点ID为空 → 校验终点名称是否为下料线 + if ((endLocationId == null || endLocationId == 0) && !DROPOFF_CONVEYOR_LINE_NAME.equals(endName)) { + throw new IllegalArgumentException("请检查运送线终点位置异常"); + } + } + + /** + * 判断是否为「下料输送线」场景 + */ + private boolean isDropoffConveyorLineScenario(ReturnToWarehouseDto dto) { + Long endLocationId = dto.getEndLocationId(); + return endLocationId == null || endLocationId == 0; + } + + /** + * 处理「下料输送线」场景的AGV调度 + */ + private R handleDropoffConveyorLineScenario(Station targetStation, List taskList) { + String stationCode = targetStation.getStationCode(); + // 1. 占用站点 + updateStationStatus(targetStation, STATUS_OCCUPIED); + + try { + // 2. 获取AGV任务类型并调用调度接口 + String taskType = agvTaskTypeUtil.getTaskType(Integer.valueOf(targetStation.getStationPosition()), true); + boolean agvResult = iPipelineOrderBoxService.genAgvSchedulingTask( + taskType, stationCode, DROPOFF_CONVEYOR_LINE, EQUIPMENT_TYPE_AGV, taskList.get(0) + ); + + if (agvResult) { + log.info("AGV调度成功(下料线场景),站点编号:{}", stationCode); + return R.success(); + } else { + throw new RuntimeException("调用AGV小车异常"); } + } catch (Exception e) { + // 3. AGV调用失败 → 回滚站点状态 + updateStationStatus(targetStation, STATUS_FREE); + throw e; + } + } - // 3.3 解绑订单(更新绑定状态为未绑定) - List orderBindList = iOrderBindService.list(new LambdaQueryWrapper().eq(OrderBind::getTaskId, task.getId())); - if (!CollectionUtils.isEmpty(orderBindList)) { - for (OrderBind orderBind : orderBindList) { - orderBind.setBindingStatus(STATUS_UNBINDED); - iOrderBindService.updateById(orderBind); - } + /** + * 处理「目标站点」场景的AGV调度 + */ + private R handleTargetStationScenario(Station targetStation, ReturnToWarehouseDto dto, List taskList) { + String sourceStationCode = targetStation.getStationCode(); + Long endLocationId = dto.getEndLocationId(); + + // 1. 查询终点空闲站点 + Station endStation = getFreeStationByWcId(endLocationId); + + // 2. 占用源站点 + 预占用终点站点 + updateStationStatus(targetStation, STATUS_OCCUPIED); + updateStationStatus(endStation, PRE_STATUS_OCCUPIED); + + try { + // 3. 获取AGV任务类型并调用调度接口 + String taskType = agvTaskTypeUtil.getTaskType(Integer.valueOf(targetStation.getStationPosition()), false); + boolean agvResult = iPipelineOrderBoxService.genAgvSchedulingTask( + taskType, sourceStationCode, endStation.getStationCode(), EQUIPMENT_TYPE_AGV, taskList.get(0) + ); + + if (agvResult) { + log.info("AGV调度成功(目标站点场景),源站点:{},终点站点:{}", sourceStationCode, endStation.getStationCode()); + return R.success(); + } else { + throw new RuntimeException("调用AGV小车异常"); } + } catch (Exception e) { + // 4. AGV调用失败 → 回滚两个站点状态 + updateStationStatus(targetStation, STATUS_FREE); + updateStationStatus(endStation, STATUS_FREE); + throw e; + } + } -// // 3.4 结束任务(更新任务状态为已完成) -// task.setTaskStatus(STATUS_FINISHED); -// iTaskService.updateById(task); + /** + * 根据WCID查询空闲的终点站点(不存在则抛异常) + */ + private Station getFreeStationByWcId(Long wcId) { + LambdaQueryWrapper endStationQuery = new LambdaQueryWrapper() + .eq(Station::getWcId, wcId) + .eq(Station::getStationStatus, STATUS_FREE); + List endStationList = iStationService.list(endStationQuery); + + if (endStationList == null || endStationList.isEmpty()) { + log.warn("结束站点异常,WCID:{}", wcId); + throw new IllegalArgumentException("结束站点异常"); } + return endStationList.get(0); + } - return R.success(); + /** + * 统一更新站点状态(封装重复逻辑) + */ + private void updateStationStatus(Station station, Integer newStatus) { + station.setStationStatus(newStatus); + boolean updateResult = iStationService.updateById(station); + if (!updateResult) { + log.error("站点状态更新失败,站点编号:{},目标状态:{}", station.getStationCode(), newStatus); + throw new RuntimeException("站点状态更新失败"); + } + log.debug("站点状态更新成功,站点编号:{},状态:{}", station.getStationCode(), newStatus); + } + + @Override + public R returnToWarehouseList() { + List stationList = iStationService.list(new LambdaQueryWrapper().eq(Station::getStationStatus, STATUS_FREE)); + ArrayList bsWorkCenterVOList = new ArrayList<>(); + BsWorkCenterVO bsWorkCenterVO = new BsWorkCenterVO(); + bsWorkCenterVO.setWcName(DROPOFF_CONVEYOR_LINE_NAME); + bsWorkCenterVOList.add(bsWorkCenterVO); + if (!stationList.isEmpty()) { + List list = stationList.stream().map(Station::getWcId).distinct().collect(Collectors.toList()); + List bwList = bsWorkCenterService.getByIds(list); + if (!bwList.isEmpty()) { + bwList.forEach(s->{bsWorkCenterVOList.add(s);}); + } + + } + return R.data(bsWorkCenterVOList); } /** * 批量保存订单与任务的绑定关系 * 核心:创建订单绑定记录并批量插入,插入失败则回滚任务(删除已创建的任务) * - * @param taskId 任务ID(关联箱条码) + * @param taskId 任务ID(关联箱条码) * @param orderIdList 订单ID列表 * @return R 保存结果 - * - 成功:R.success() - * - 失败:R.fail(),删除任务并返回异常信息 + * - 成功:R.success() + * - 失败:R.fail(),删除任务并返回异常信息 */ private R saveOrderBindingList(Long taskId, ArrayList orderIdList) { ArrayList orderBindList = new ArrayList<>(); @@ -262,7 +451,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { // 批量插入绑定记录,失败则删除任务 if (iOrderBindService.saveBatch(orderBindList)) { return R.success(); - }else { + } else { iTaskService.removeById(taskId); // 回滚:删除已创建的任务 return R.fail("订单绑定箱条码异常"); } @@ -292,8 +481,8 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { * * @param task 任务对象(包含工位ID) * @return R 分配结果 - * - 成功:R.data(task),任务对象已填充站点/库位ID - * - 失败:R.fail(),提示库位繁忙 + * - 成功:R.data(task),任务对象已填充站点/库位ID + * - 失败:R.fail(),提示库位繁忙 */ private R getSiteLocation(Task task) { // 1. 查询当前工位可用的站点(状态为占用的站点) @@ -328,8 +517,8 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { * * @param boxBarcode 箱条码 * @return R 校验结果 - * - 成功:R.success()(无运行中任务) - * - 失败:R.fail()(存在运行中任务) + * - 成功:R.success()(无运行中任务) + * - 失败:R.fail()(存在运行中任务) */ private R checkBoxBarcodeRunningTask(String boxBarcode) { // 查询箱条码对应的所有任务 @@ -361,8 +550,8 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { * * @param orderIdList 订单ID列表 * @return R 校验结果 - * - 成功:R.success()(无已绑定订单) - * - 失败:R.fail()(存在已绑定订单,返回对应流程卡号) + * - 成功:R.success()(无已绑定订单) + * - 失败:R.fail()(存在已绑定订单,返回对应流程卡号) */ private R checkOrderIdBoundStatus(List orderIdList) { // 无订单号,直接通过校验 diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IPipelineOrderBoxServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IPipelineOrderBoxServiceImpl.java new file mode 100644 index 000000000..925c8d598 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IPipelineOrderBoxServiceImpl.java @@ -0,0 +1,123 @@ +package org.springblade.desk.logistics.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springblade.core.tool.api.R; +import org.springblade.desk.logistics.pojo.entity.Location; +import org.springblade.desk.logistics.pojo.entity.OrderBind; +import org.springblade.desk.logistics.pojo.entity.Station; +import org.springblade.desk.logistics.pojo.entity.Task; +import org.springblade.desk.logistics.service.*; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.springblade.desk.logistics.pojo.entity.OrderBind.STATUS_UNBINDED; +import static org.springblade.desk.logistics.pojo.entity.Station.STATUS_OCCUPIED; + +@Service +@Slf4j +public class IPipelineOrderBoxServiceImpl implements IPipelineOrderBoxService { + /** + * 任务服务:处理箱绑定任务的创建、状态更新、删除等 + */ + private final ITaskService iTaskService; + /** + * 站点服务:处理站点状态(占用/空闲)管理 + */ + private final IStationService iStationService; + + /** + * 库位服务:处理库位状态(占用/空闲)管理 + */ + private final ILocationService iLocationService; + /** + * 订单绑定服务:处理订单与任务的绑定关系维护 + */ + private final IOrderBindService iOrderBindService; + + /** + * 任务运行中状态集合:包含任务从启动到待入库的所有中间状态 + * 用于判断箱条码是否存在未完成的运行任务 + */ + private static final Set RUNNING_STATUSES = new HashSet<>(); + + static { + // 初始化运行中任务状态 + RUNNING_STATUSES.add(Task.STATUS_START); // 任务启动 + RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_START); // 输送机启动 + RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_END); // 输送机结束 + RUNNING_STATUSES.add(Task.STATUS_STATION); // 站点状态 + RUNNING_STATUSES.add(Task.STATUS_LOCATION); // 库位状态 + RUNNING_STATUSES.add(Task.STATUS_WAITING); // 等待状态 + RUNNING_STATUSES.add(Task.STATUS_STATION_RECEIVE);// 站点接收 + RUNNING_STATUSES.add(Task.STATUS_BACK_TO_STORAGE);// 返库状态 + } + + public IPipelineOrderBoxServiceImpl(ITaskService iTaskService, IStationService iStationService, ILocationService iLocationService, IOrderBindService iOrderBindService) { + this.iTaskService = iTaskService; + this.iStationService = iStationService; + this.iLocationService = iLocationService; + this.iOrderBindService = iOrderBindService; + } + + + /** + * 箱条码与订单解绑 + * 流程:参数校验 → 查询运行中任务 → 重置站点/库位状态 → 解绑订单 → 结束任务 + * + * @param boxBarcode 箱条码 + * @return R 解绑结果 + * - 成功:R.success() + * - 失败:R.fail(),携带具体失败原因(如箱条码为空) + */ + @Override + public R boxOrderUnbind(String boxBarcode) { + // 1. 参数非空校验 + if (boxBarcode.isEmpty()) { + log.warn("箱绑定参数为空或箱条码缺失"); + return R.fail("箱条码不能为空"); + } + + // 2. 查询该箱条码对应的运行中任务 + List taskList = iTaskService.list( + new LambdaQueryWrapper().eq(Task::getBoxBarcode, boxBarcode).in(false, Task::getTaskStatus, RUNNING_STATUSES) + ); + + // 3. 遍历任务,重置站点/库位状态 + 解绑订单 + 结束任务 + for (Task task : taskList) { + // 3.1 重置站点状态为占用(释放站点) + if (task.getStationId() != null && task.getStationId() != 0) { + Station station = iStationService.getById(task.getStationId()); + station.setStationStatus(STATUS_OCCUPIED); + iStationService.updateById(station); + } + + // 3.2 重置库位状态为占用(释放库位) + if (task.getLocationId() != null && task.getLocationId() != 0) { + Location location = iLocationService.getById(task.getLocationId()); + location.setLocationStatus(STATUS_OCCUPIED); + iLocationService.updateById(location); + } + + // 3.3 解绑订单(更新绑定状态为未绑定) + List orderBindList = iOrderBindService.list(new LambdaQueryWrapper().eq(OrderBind::getTaskId, task.getId())); + if (!CollectionUtils.isEmpty(orderBindList)) { + for (OrderBind orderBind : orderBindList) { + orderBind.setBindingStatus(STATUS_UNBINDED); + iOrderBindService.updateById(orderBind); + } + } + +// // 3.4 结束任务(更新任务状态为已完成) +// task.setTaskStatus(STATUS_FINISHED); +// iTaskService.updateById(task); + } + + return R.success(); + } + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/PipelineServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/PipelineServiceImpl.java index bac536009..6150ec3b5 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/PipelineServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/PipelineServiceImpl.java @@ -24,6 +24,7 @@ * Author: Chill Zhuang (bladejava@qq.com) */ package org.springblade.desk.logistics.service.impl; +import groovy.lang.Lazy; import lombok.extern.slf4j.Slf4j; import org.springblade.core.tool.api.R; import org.springblade.desk.logistics.constant.AgvConstant; @@ -60,7 +61,8 @@ public class PipelineServiceImpl implements IPipelineService { ILocationService locationService; @Autowired - IOrderBoxService orderBoxService; + IPipelineOrderBoxService iPipelineOrderBoxService; +// IOrderBoxService orderBoxService; @Autowired ITaskExecuteRecordService taskExecuteRecordService; @@ -80,7 +82,7 @@ public class PipelineServiceImpl implements IPipelineService { taskService.savePipelineWeigh(boxBarcode,actualWeight, Task.STATUS_RETURNED); // 3.超重处理,解绑 - R ret = orderBoxService.boxOrderUnbind(boxBarcode); + R ret = iPipelineOrderBoxService.boxOrderUnbind(boxBarcode); if(!ret.isSuccess()){ throw new ServiceException("解绑失败: "+boxBarcode); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/AgvTaskTypeUtil.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/AgvTaskTypeUtil.java index 4a9da47f3..6ca253d38 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/AgvTaskTypeUtil.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/AgvTaskTypeUtil.java @@ -15,7 +15,7 @@ public class AgvTaskTypeUtil { * @param isRecycle 是否回收 (true:空箱回收, false:正常任务) * @return 任务类型 (QM3, QM5, QM6, QM7) */ - public String getTaskType(Integer floor, Boolean isRecycle) { + public String getTaskType(Integer floor, Boolean isRecycle) { // 参数校验 if (floor == null) { log.error("楼层参数不能为空"); diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java new file mode 100644 index 000000000..94a32736a --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java @@ -0,0 +1,36 @@ +package org.springblade.desk.logistics.utils; + +import java.util.Collection; +import java.util.Map; + +public class CollectionCheckUtil { + /** + * 判断指定字段的值是否存在于目标集合中 + * + * @param fieldValue 要校验的字段参数值 + * @param targetCollection 目标集合(List、Set、Map等) + * @param 字段值的类型(泛型适配任意类型) + * @return 存在返回true,不存在返回false + * @throws IllegalArgumentException 当目标集合为空或类型不支持时抛出异常 + */ + public static boolean isFieldInCollection(T fieldValue, Object targetCollection) { + // 健壮性校验 + if (targetCollection == null) { + throw new IllegalArgumentException("目标集合不能为空"); + } + + // 处理Collection类型(List、Set等) + if (targetCollection instanceof Collection) { + return ((Collection) targetCollection).contains(fieldValue); + } + + // 处理Map类型(判断key是否存在) + if (targetCollection instanceof Map) { + return ((Map) targetCollection).containsKey(fieldValue); + } + + // 不支持的集合类型 + throw new IllegalArgumentException("不支持的集合类型:" + targetCollection.getClass().getName()); + } + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemOrderController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemOrderController.java index a7b635067..689cf7787 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemOrderController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemOrderController.java @@ -144,11 +144,30 @@ public class OemOrderController extends BladeController { return workOrderRunService.changeOemManufacturer(worId, ocId); } + + @PostMapping(value = "/reviewQualityRecords") + @ApiOperationSupport(order = 7) + @Operation(summary = "外协质量记录跳转", description = "") + public R reviewQualityRecords(@RequestBody JSONObject data) { + String deliverKey = data.getString("deliverKey"); + String url = "http://192.168.242.158:80/mms/login/login_vendorJpageZljl.jsp?LOGIN158=admin&deliverNo=" + deliverKey; + return R.success(url); + } + + @PostMapping(value = "/reviewQualification") + @ApiOperationSupport(order = 8) + @Operation(summary = "外协合格证跳转", description = "") + public R reviewQualification(@RequestBody JSONObject data) { + String deliverKey = data.getString("deliverKey"); + String url = "http://192.168.242.158:80/mms/login/login_vendorJpage.jsp?LOGIN158=admin&deliverNo=" + deliverKey; + return R.success(url); + } + /** * 报价单 自定义分页 */ @GetMapping("/priceSheetData") - @ApiOperationSupport(order = 7) + @ApiOperationSupport(order = 9) @Operation(summary = "报价单分页", description = "传入mesOemStatement") public R> priceSheetData(PriceSheetQuery priceSheetQuery, Query query) { R> pageR = erpDataOemClient.priceSheetData(priceSheetQuery, query); diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemStatementController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemStatementController.java index 53182f1e4..1f87e8f54 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemStatementController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemStatementController.java @@ -13,6 +13,7 @@ import org.springblade.core.mp.support.Query; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.Func; import org.springblade.desk.oem.pojo.excel.OemStatementExcel; +import org.springblade.desk.oem.pojo.request.OemSettleAccountsSave; import org.springblade.desk.oem.pojo.request.StatementQuery; import org.springblade.desk.oem.pojo.vo.StatementVO; import org.springframework.web.bind.annotation.*; @@ -107,6 +108,16 @@ public class OemStatementController extends BladeController { return R.status(mesOemStatementService.deleteLogic(Func.toLongList(ids))); } + /** + * 外协结算 + */ + @PostMapping("/oemSettleAccounts") + @ApiOperationSupport(order = 8) + @Operation(summary = "外协结算", description = "") + public R oemSettleAccounts(@Valid @RequestBody OemSettleAccountsSave oemSettleAccountsSave) { + return mesOemStatementService.oemSettleAccounts(oemSettleAccountsSave.getStatementList(), oemSettleAccountsSave.getPrice(), oemSettleAccountsSave.getPutStoreDate()); + } + /** * 导出数据 diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/PlatingTypeRulesController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/PlatingTypeRulesController.java new file mode 100644 index 000000000..183f4b57a --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/PlatingTypeRulesController.java @@ -0,0 +1,162 @@ +package org.springblade.desk.oem.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import lombok.AllArgsConstructor; +import jakarta.validation.Valid; + +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.annotation.IsAdmin; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.utils.Func; +import org.springblade.desk.basic.util.ExcelExtUtil; +import org.springblade.desk.oem.pojo.excel.OemProcessImport; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesExcel; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesImport; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import org.springblade.desk.oem.pojo.vo.PlatingTypeRulesVO; +import org.springblade.desk.oem.wrapper.PlatingTypeRulesWrapper; +import org.springblade.desk.oem.service.IPlatingTypeRulesService; +import org.springblade.core.boot.ctrl.BladeController; +import org.springblade.core.tool.utils.DateUtil; +import org.springblade.core.excel.util.ExcelUtil; +import org.springblade.core.tool.constant.BladeConstant; + +import java.util.Map; +import java.util.List; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MultipartFile; + +/** + * 外协镀种规则 控制器 + * + * @author qyl + * @since 2026-03-03 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/mesPlatingTypeRules") +@Tag(name = "外协镀种规则", description = "外协镀种规则接口") +public class PlatingTypeRulesController extends BladeController { + + private final IPlatingTypeRulesService mesPlatingTypeRulesService; + + /** + * 外协镀种规则 详情 + */ + @GetMapping("/detail") + @ApiOperationSupport(order = 1) + @Operation(summary = "详情", description = "传入mesPlatingTypeRules") + public R detail(PlatingTypeRulesEntity mesPlatingTypeRules) { + PlatingTypeRulesEntity detail = mesPlatingTypeRulesService.getOne(Condition.getQueryWrapper(mesPlatingTypeRules)); + return R.data(PlatingTypeRulesWrapper.build().entityVO(detail)); + } + + /** + * 外协镀种规则 自定义分页 + */ + @GetMapping("/page") + @ApiOperationSupport(order = 3) + @Operation(summary = "分页", description = "传入mesPlatingTypeRules") + public R> page(PlatingTypeRulesVO mesPlatingTypeRules, Query query) { + IPage pages = mesPlatingTypeRulesService.selectPlatingTypeRulesPage(Condition.getPage(query), mesPlatingTypeRules); + return R.data(pages); + } + + /** + * 外协镀种规则 新增 + */ + @PostMapping("/save") + @ApiOperationSupport(order = 4) + @Operation(summary = "新增", description = "传入mesPlatingTypeRules") + public R save(@Valid @RequestBody PlatingTypeRulesEntity mesPlatingTypeRules) { + return R.status(mesPlatingTypeRulesService.save(mesPlatingTypeRules)); + } + + /** + * 外协镀种规则 修改 + */ + @PostMapping("/update") + @ApiOperationSupport(order = 5) + @Operation(summary = "修改", description = "传入mesPlatingTypeRules") + public R update(@Valid @RequestBody PlatingTypeRulesEntity mesPlatingTypeRules) { + return R.status(mesPlatingTypeRulesService.updateById(mesPlatingTypeRules)); + } + + /** + * 外协镀种规则 新增或修改 + */ + @PostMapping("/submit") + @ApiOperationSupport(order = 6) + @Operation(summary = "新增或修改", description = "传入mesPlatingTypeRules") + public R submit(@Valid @RequestBody PlatingTypeRulesEntity mesPlatingTypeRules) { + return R.status(mesPlatingTypeRulesService.saveOrUpdate(mesPlatingTypeRules)); + } + + /** + * 外协镀种规则 删除 + */ + @PostMapping("/remove") + @ApiOperationSupport(order = 7) + @Operation(summary = "逻辑删除", description = "传入ids") + public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) { + return R.status(mesPlatingTypeRulesService.deleteLogic(Func.toLongList(ids))); + } + + + /** + * 导出数据 + */ + @IsAdmin + @GetMapping("/export-mesPlatingTypeRules") + @ApiOperationSupport(order = 9) + @Operation(summary = "导出数据", description = "传入mesPlatingTypeRules") + public void exportPlatingTypeRules(@Parameter(hidden = true) @RequestParam Map mesPlatingTypeRules, BladeUser bladeUser, HttpServletResponse response) { + QueryWrapper queryWrapper = Condition.getQueryWrapper(mesPlatingTypeRules, PlatingTypeRulesEntity.class); + //if (!AuthUtil.isAdministrator()) { + // queryWrapper.lambda().eq(PlatingTypeRules::getTenantId, bladeUser.getTenantId()); + //} + //queryWrapper.lambda().eq(PlatingTypeRulesEntity::getIsDeleted, BladeConstant.DB_NOT_DELETED); + List list = mesPlatingTypeRulesService.exportPlatingTypeRules(queryWrapper); + ExcelUtil.export(response, "外协镀种规则数据" + DateUtil.time(), "外协镀种规则数据表", list, PlatingTypeRulesExcel.class); + } + + /** + * 下载Excel模板 + */ + @GetMapping("/downloadExcelTemplate") + @ApiOperationSupport(order = 10) + @Operation(summary = "下载Excel模板", description = "") + public ResponseEntity downloadExcelTemplate() { + return ExcelExtUtil.downloadXlsTemplate( + "Excel/oem/外协镀种规则.xls", + "外协镀种规则.xls"); + } + + /** + * 导入Excel + */ + @PostMapping("/importExcel") + @ApiOperationSupport(order = 11) + @Operation(summary = "导入Excel", description = "MultipartFile") + public R importExcel(@RequestParam("file") MultipartFile file) { + R checkR = ExcelExtUtil.importExcelCheck(file); + if (checkR != null) { + return checkR; + } + List importList = ExcelUtil.read( + file, 0, 1, PlatingTypeRulesImport.class + ); + return mesPlatingTypeRulesService.saveExcelData(importList); + } +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemAndAbilityMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemAndAbilityMapper.xml index bbef7423e..daa092173 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemAndAbilityMapper.xml +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemAndAbilityMapper.xml @@ -28,17 +28,17 @@ oaa.*, oem.oc_name AS oem_name, oem.code AS oem_code, - pa.code AS ca_code, - pa.name AS ca_name + ca.ca_code, + ca.ca_name from MES_OEM_AND_ABILITY oaa LEFT JOIN BS_OEM oem ON oaa.oc_id = oem.id - LEFT JOIN BA_PROCESS_ABILITY pa ON oaa.ca_id = pa.id + LEFT JOIN BS_CRAFT_ABILITY ca ON oaa.ca_id = ca.id where oaa.is_deleted = 0 AND oem.oc_name LIKE CONCAT('%', CONCAT(#{query.oemName}, '%')) - AND pa.id = #{query.caId} + AND ca.id = #{query.caId} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemStatementMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemStatementMapper.xml index eab68e013..979331de4 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemStatementMapper.xml +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemStatementMapper.xml @@ -20,11 +20,29 @@ + - + + + + + + + + + + + + + + + + + + @@ -44,10 +62,13 @@ + + + @@ -62,11 +83,6 @@ - - - - - diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.java new file mode 100644 index 000000000..bf0d8d476 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.java @@ -0,0 +1,39 @@ +package org.springblade.desk.oem.mapper; + +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesExcel; +import org.springblade.desk.oem.pojo.vo.PlatingTypeRulesVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 外协镀种规则 Mapper 接口 + * + * @author qyl + * @since 2026-03-03 + */ +public interface PlatingTypeRulesMapper extends BaseMapper { + + /** + * 自定义分页 + * + * @param page 分页参数 + * @param mesPlatingTypeRules 查询参数 + * @return List + */ + List selectPlatingTypeRulesPage(IPage page, PlatingTypeRulesVO mesPlatingTypeRules); + + + /** + * 获取导出数据 + * + * @param queryWrapper 查询条件 + * @return List + */ + List exportPlatingTypeRules(@Param("ew") Wrapper queryWrapper); + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.xml new file mode 100644 index 000000000..befcddb8e --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/IPlatingTypeRulesService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/IPlatingTypeRulesService.java new file mode 100644 index 000000000..1e54864de --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/IPlatingTypeRulesService.java @@ -0,0 +1,46 @@ +package org.springblade.desk.oem.service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import org.springblade.core.tool.api.R; +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesExcel; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesImport; +import org.springblade.desk.oem.pojo.vo.PlatingTypeRulesVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.core.mp.base.BaseService; + +import java.util.List; + +/** + * 外协镀种规则 服务类 + * + * @author qyl + * @since 2026-03-03 + */ +public interface IPlatingTypeRulesService extends BaseService { + /** + * 自定义分页 + * + * @param page 分页参数 + * @param mesPlatingTypeRules 查询参数 + * @return IPage + */ + IPage selectPlatingTypeRulesPage(IPage page, PlatingTypeRulesVO mesPlatingTypeRules); + + + /** + * 导出数据 + * + * @param queryWrapper 查询条件 + * @return List + */ + List exportPlatingTypeRules(Wrapper queryWrapper); + + /** + * 导入 + * + * @param list + * @return + */ + R saveExcelData(List list); +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/OemStatementServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/OemStatementServiceImpl.java index 5098ce2cb..c2804fd27 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/OemStatementServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/OemStatementServiceImpl.java @@ -1,20 +1,25 @@ package org.springblade.desk.oem.service.impl; +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.annotation.Resource; import org.springblade.core.mp.support.Query; import org.springblade.core.tool.api.R; -import org.springblade.desk.dashboard.utils.DateUtils; +import org.springblade.desk.oem.mapper.PlatingTypeRulesMapper; import org.springblade.desk.oem.pojo.entity.OemStatementEntity; +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; import org.springblade.desk.oem.pojo.excel.OemStatementExcel; import org.springblade.desk.oem.pojo.request.PriceSheetQuery; import org.springblade.desk.oem.pojo.request.StatementQuery; -import org.springblade.desk.oem.pojo.vo.OemStatementVO; import org.springblade.desk.oem.mapper.OemStatementMapper; import org.springblade.desk.oem.pojo.vo.PriceSheetVO; import org.springblade.desk.oem.pojo.vo.StatementVO; import org.springblade.desk.oem.service.IOemStatementService; +import org.springblade.desk.util.PriceMatcher; import org.springblade.erpdata.feign.IErpDataOemClient; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -22,8 +27,7 @@ import org.springblade.core.mp.base.BaseServiceImpl; import java.math.BigDecimal; import java.time.LocalDate; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -38,6 +42,9 @@ public class OemStatementServiceImpl extends BaseServiceImpl selectOemStatementPage(IPage page, StatementQuery mesOemStatement) { return page.setRecords(baseMapper.selectOemStatementPage(page, mesOemStatement)); @@ -55,31 +62,660 @@ public class OemStatementServiceImpl extends BaseServiceImpl statementVOS, BigDecimal price, LocalDate putStoreDate) { - //以外协厂商分组的Map<厂家代码, 待结算工序结算单列表> - Map> oemAndStatementMap = statementVOS.stream().collect(Collectors.groupingBy(StatementVO::getOemCode)); + //1.以外协厂商分组的Map<厂家名称, 待结算工序结算单列表> + Map> oemAndStatementMap = statementVOS.stream().collect(Collectors.groupingBy(StatementVO::getOcName)); for (Map.Entry> listEntry : oemAndStatementMap.entrySet()) { //外协厂商下全部需要结算的结算单 List statementVOList = listEntry.getValue(); - //以外协代码,日期查出的全部报价单 - String oemCode = listEntry.getKey(); - PriceSheetQuery query = new PriceSheetQuery(); - query.setOcCode(oemCode); - query.setInDateStart(putStoreDate); - query.setInDateEnd(putStoreDate); - R> pageR = erpDataOemClient.priceSheetData(query, new Query() {{ - setSize(99999); - }}); - //外协厂商下规定日期内的全部报价单 - List priceSheetVOList = null; - if (pageR != null && pageR.getData() != null && pageR.getData().getRecords() != null && pageR.getData().getRecords().size() > 0) { - priceSheetVOList = pageR.getData().getRecords(); + //2.以外协名称,日期查出的全部报价单 + String oemName = listEntry.getKey(); + List priceSheetAllList = getPriceSheets(oemName, putStoreDate); + if (priceSheetAllList.isEmpty()) { + //【结算异常】 + statementVOList.forEach(statementVO -> { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】匹配无报价记录", oemName)); + }); + } else { + //工序分组Map<工序, 报价列表> + Map> priceSheetMap = priceSheetAllList.stream().collect(Collectors.groupingBy(PriceSheetVO::getGxinfo)); + /*statementVOList.forEach(statementVO -> { + List matchedPriceSheets = MatchTheQuotations(statementVO, priceSheetMap); + if (matchedPriceSheets.isEmpty()) { + return; + } + statementVO.setPriceSheetList(matchedPriceSheets); + });*/ + //3.为每个结算单匹配报价集合 + statementVOList.forEach(statementVO -> { + List matchedPriceSheets = MatchTheQuotations(statementVO, priceSheetMap); + if (matchedPriceSheets.isEmpty()) { + return; + } + statementVO.setPriceSheetList(matchedPriceSheets); + //4.匹配规则,过滤出唯一报价 + //①.匹配车间订单号 + if (ruleWoNo(statementVO)) { + return; + } + //②.匹配物料名称和质量等级 + if (rulePartNameAndProdIdent(statementVO)) { + return; + } + //③.匹配金价银价 + if (ruleGoldAndSilverPrices(statementVO, price)) { + return; + } + //④.涂色标、涂色带、涂箭头 + if (ruleColor(statementVO)) { + return; + } + //⑤.物料号匹配 + if (ruleGoods(statementVO)) { + return; + } + //⑥.阶梯价匹配 + if (ruleTieredPricing(statementVO)) { + return; + } + }); } - statementVOList.forEach(statementVO -> { + //保存 + List saves = statementVOList.stream() + .map(statementVO -> { + OemStatementEntity entity = new OemStatementEntity(); + BeanUtils.copyProperties(statementVO, entity); + entity.setUpdateTime(new Date()); + return entity; + }) + .collect(Collectors.toList()); + baseMapper.insertOrUpdate(saves); + } + return R.success("操作完成"); + + } + + /** + * 获取报价单列表 + */ + private List getPriceSheets(String oemName, LocalDate putStoreDate) { + PriceSheetQuery query = new PriceSheetQuery(); + query.setOcName(oemName); + query.setInDateStart(putStoreDate); + query.setInDateEnd(putStoreDate); + +// R> pageR = erpDataOemClient.priceSheetData(query, new Query() {{ +// setSize(99999); +// }}); + +// if (pageR != null && pageR.getData() != null) { +// return pageR.getData().getRecords(); +// } + return Collections.emptyList(); + } + + /** + * 为结算单匹配报价集合 + * + * @param statementVO 外协厂家下镀后入库的外协工序结算单 + * @param priceSheetMap 外协厂家下有效期内的全部工序报价 + */ + private List MatchTheQuotations(StatementVO statementVO, Map> priceSheetMap) { + String psName = statementVO.getPsName(); + if (!priceSheetMap.containsKey(psName)) { + //【结算异常】 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】匹配无报价记录", statementVO.getOcName(), psName)); + return null; + } + //获得外协厂商该工序下报价单列表 + return priceSheetMap.get(psName); + } + + /** + * 规则:匹配车间订单号 + * + * @param statementVO + * @return + */ + private boolean ruleWoNo(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //取出匹配车间订单号的报价和无车间订单号的报价 + Map> woNoPriceSheetMap = priceSheetList.stream() + .collect(Collectors.groupingBy( + priceSheet -> { + String wono = priceSheet.getWono(); + return wono == null || wono.trim().isEmpty() ? "EMPTY_WONO" : wono; + }, + Collectors.toList() + )); + //匹配车间订单号报价 + if (woNoPriceSheetMap.containsKey(statementVO.getWoCode())) { + List woNoPriceSheetList = woNoPriceSheetMap.get(statementVO.getWoCode()); + //多条【结算异常】 + if (woNoPriceSheetList.size() > 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,工作订单号【%s】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), statementVO.getWoCode())); + //结算异常:多条报价记录结算结果 + return true; + } + PriceSheetVO priceSheet = woNoPriceSheetList.get(0); + //唯一使用此报价单**结算** + BigDecimal unitPrice = new BigDecimal(priceSheet.getPrice()); + BigDecimal qty = new BigDecimal(statementVO.getMakeQty()); + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setUnitPrice(unitPrice); + statementVO.setUnit(priceSheet.getPrtum()); + statementVO.setTotalPrice(unitPrice.multiply(qty)); + statementVO.setMemo("结算中"); + statementVO.setQuotation(priceSheet.getSeqid()); + //使用此报价 + return true; + } else { + //筛选出无车间订单号报价单列表 + priceSheetList = woNoPriceSheetMap.get("EMPTY_WONO"); + if (priceSheetList.size() < 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + //结算异常:无报价记录结算结果 + return true; + } else { + statementVO.setPriceSheetList(priceSheetList); + //结束当前规则匹配,进入下一规则匹配 + return false; + } + } + } + + /** + * 规则:匹配物料名称和质量等级 + * + * @param statementVO + * @return + */ + private boolean rulePartNameAndProdIdent(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //报价单判断同时满足物料名称和质量等级 || 为空 + priceSheetList = priceSheetList.stream() + .filter(priceSheet -> matchesCondition1(priceSheet, statementVO)) + .filter(priceSheet -> matchesCondition2(priceSheet, statementVO)) + .collect(Collectors.toList()); + //无报价单【结算异常】 + if (priceSheetList.size() < 1) { + //结算异常:无报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,物料名【%s】,质量等级【%s】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName(), statementVO.getPartName(), statementVO.getProdIdent())); + return true; + } + //保存结果,结束当前规则匹配,进入下一规则匹配 + statementVO.setPriceSheetList(priceSheetList); + return false; + } + + /** + * 规则:金价银价 + * + * @param statementVO + * @return + */ + private boolean ruleGoldAndSilverPrices(StatementVO statementVO, BigDecimal price) { + List priceSheetList = statementVO.getPriceSheetList(); + String plateGoodsCode = statementVO.getPlateGoodsCode(); + //判断传入参数的当前金价银价 > 0 && 零件镀层物料编码不为空,则需匹配规则 + if (price.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isEmpty(plateGoodsCode)) { + //取出所有备注 + Map> remarkPriceSheetMap = priceSheetList.stream() + .filter(priceSheet -> { + String remark = priceSheet.getRemark(); + return remark != null && !remark.trim().isEmpty(); + }) + .collect(Collectors.groupingBy( + PriceSheetVO::getRemark, + Collectors.toList() + )); + Set remarksByPrice = PriceMatcher.findRemarksByPriceStream(remarkPriceSheetMap.keySet(), price); + if (remarksByPrice.size() < 1) { + //结算异常:无报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,金价银价【%s】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName(), price)); + return true; + } + //保存结果,结束当前规则匹配,进入下一规则匹配 + List priceSheetVOList = remarkPriceSheetMap.entrySet().stream() + .filter(entry -> remarksByPrice.contains(entry.getKey())) // 过滤key在keys中的条目 + .flatMap(entry -> entry.getValue().stream()) // 将List扁平化为PriceSheetVO流 + .collect(Collectors.toList()); + statementVO.setPriceSheetList(priceSheetVOList); + return false; + } + //结束当前规则匹配,进入下一规则匹配 + return false; + } + + /** + * 涂色标、涂色带、涂箭头匹配规则 + * + * @param statementVO + * @return + */ + private boolean ruleColor(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //结算单色标色带箭头数量>0,需要匹配报价里色标色带箭头 + //如果结算单没有数量,直接返回false进入下个规则 + if (!hasColorCount(statementVO)) { + //结束当前规则匹配,进入下一规则匹配 + return false; + } + //涂色标、涂色带、涂箭头的报价集合 + Map> prtnoPriceSheetMap = priceSheetList.stream() + .filter(priceSheet -> { + String prtno = priceSheet.getPrtno(); + return prtno != null && !prtno.trim().isEmpty() && ("涂色标".equals(prtno) || "涂色带".equals(prtno) || "涂箭头".equals(prtno)); + }) + .collect(Collectors.groupingBy( + PriceSheetVO::getPrtno, + Collectors.toList() + )); + // 如果没有任何报价记录 + if (prtnoPriceSheetMap.isEmpty()) { + //结算异常:无报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】涂色标、涂色带、涂箭头匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + //总价 + BigDecimal totalPrice = BigDecimal.ZERO; + //涂箭头 + Integer tjtNum = StringUtils.isNotEmpty(statementVO.getTjtNum()) ? Integer.valueOf(statementVO.getTjtNum()) : 0; + //涂色标 + Integer tsbNum = StringUtils.isNotEmpty(statementVO.getTsbNum()) ? Integer.valueOf(statementVO.getTsbNum()) : 0; + //涂色带 + Integer tsdNum = StringUtils.isNotEmpty(statementVO.getTsdNum()) ? Integer.valueOf(statementVO.getTsdNum()) : 0; + //报价单号 + String quotation = ""; + if (tjtNum > 0 && prtnoPriceSheetMap.containsKey("涂箭头")) { + List tjtPriceSheetList = prtnoPriceSheetMap.get("涂箭头"); + if (tjtPriceSheetList.size() > 1) { + //结算异常:多条报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,涂箭头数量【%s】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), tjtNum)); + return true; + } + //唯一使用此报价单**结算** + BigDecimal unitPrice = new BigDecimal(tjtPriceSheetList.get(0).getPrice()); + BigDecimal itemTotalPrice = unitPrice.multiply(BigDecimal.valueOf(tjtNum)); + totalPrice = totalPrice.add(itemTotalPrice); + quotation = tjtPriceSheetList.get(0).getSeqid(); + } + if (tsdNum > 0 && prtnoPriceSheetMap.containsKey("涂色带")) { + List tsdPriceSheetList = prtnoPriceSheetMap.get("涂色带"); + if (tsdPriceSheetList.size() > 1) { + //结算异常:多条报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,涂色带数量【%s】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), tsdNum)); + return true; + } + //唯一使用此报价单**结算** + BigDecimal unitPrice = new BigDecimal(tsdPriceSheetList.get(0).getPrice()); + BigDecimal itemTotalPrice = unitPrice.multiply(BigDecimal.valueOf(tsdNum)); + totalPrice = totalPrice.add(itemTotalPrice); + quotation = tsdPriceSheetList.get(0).getSeqid(); + } + if (tsbNum > 0 && prtnoPriceSheetMap.containsKey("涂色标")) { + List tsbPriceSheetList = prtnoPriceSheetMap.get("涂色标"); + if (tsbPriceSheetList.size() > 1) { + //结算异常:多条报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,涂色标数量【%s】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), tsbNum)); + return true; + } + //唯一使用此报价单**结算** + BigDecimal unitPrice = new BigDecimal(tsbPriceSheetList.get(0).getPrice()); + BigDecimal itemTotalPrice = unitPrice.multiply(BigDecimal.valueOf(tsbNum)); + totalPrice = totalPrice.add(itemTotalPrice); + quotation = tsbPriceSheetList.get(0).getSeqid(); + } + //如总价大于0,则报价成功 + if (totalPrice.compareTo(BigDecimal.ZERO) > 0) { + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setTotalPrice(totalPrice); + statementVO.setMemo("结算中"); + statementVO.setQuotation(quotation); + return true; + } else { + //结算异常:多条报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】涂色标、涂色带、涂箭头匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + } + + /** + * 规则:物料号匹配 + * + * @param statementVO + * @return + */ + private boolean ruleGoods(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //1.结算单的镀种、零件号、镀层厚度,三个维度分别匹配报价的物料号,匹配出单一维度的报价 + StatementVO statementPlate = BeanUtil.copyProperties(statementVO, StatementVO.class); + StatementVO statementPartCode = BeanUtil.copyProperties(statementVO, StatementVO.class); + StatementVO statementPlateThickness = BeanUtil.copyProperties(statementVO, StatementVO.class); + //2.统计结果为 true 的规则数量 + int trueCount = 0; + if (rulePlate(statementPlate)) { + statementVO.setPriceSheetList(statementPlate.getPriceSheetList()); + trueCount++; + } + if (rulePartCode(statementPartCode)) { + statementVO.setPriceSheetList(statementPartCode.getPriceSheetList()); + trueCount++; + } + if (rulePlateThickness(statementPlateThickness)) { + statementVO.setPriceSheetList(statementPlateThickness.getPriceSheetList()); + trueCount++; + } + if (trueCount == 1) { + //保存结果,结束当前规则匹配,进入下一规则匹配 + return false; + } else if (trueCount > 1) { + //结算异常:多条报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,物料号匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } else { + //结算异常:无报价记录结算结果 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,物料号匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + } - }); + /** + * 规则:镀种匹配 + * + * @param statementVO + * @return + */ + private boolean rulePlate(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //结算单的镀种维度匹配报价的物料号 + String plate = statementVO.getPlate(); + if (StringUtils.isEmpty(plate)) { + return false; + } + Map> map = priceSheetList.stream().collect(Collectors.groupingBy(PriceSheetVO::getPrtno)); + //1.精确匹配,完整的镀种 + if (map.containsKey(plate)) { + statementVO.setPriceSheetList(map.get(plate)); + return true; } - return null; + //2.使用模糊查询。根据订单中的镀种,到镀种映射表中查询对应的代码,再根据代码查找报价,适用于:Ap.Ni15、Ap.Ni20有同一个报价Ap.Ni%Cu%Xn% + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); + queryWrapper.eq(PlatingTypeRulesEntity::getOrderPlat, plate) + .orderByDesc(PlatingTypeRulesEntity::getCreateTime) // 按创建时间降序 + .last("AND ROWNUM = 1"); // 只取第一条 + PlatingTypeRulesEntity platingTypeRulesEntity = platingTypeRulesMapper.selectOne(queryWrapper); + if (platingTypeRulesEntity == null || StringUtils.isBlank(platingTypeRulesEntity.getQuotationPlat())) { + return false; + } + if (map.containsKey(platingTypeRulesEntity.getQuotationPlat())) { + statementVO.setPriceSheetList(map.get(plate)); + return true; + } + return true; } + /** + * 规则:零件号匹配 + * + * @param statementVO + * @return + */ + private boolean rulePartCode(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //结算单的零件号维度匹配报价的物料号 + String partCode = statementVO.getPartCode(); + if (StringUtils.isEmpty(partCode)) { + return false; + } + Map> map = priceSheetList.stream().collect(Collectors.groupingBy(PriceSheetVO::getPrtno)); + //1.精确匹配,完整的零件号 + if (map.containsKey(partCode)) { + statementVO.setPriceSheetList(map.get(partCode)); + return true; + } + //2.模糊查询报价单中为一类零件号, 如81E6-%螺母 + Map> newMap = map.entrySet().stream() + .filter(entry -> entry.getKey().contains("-%")) + .collect(Collectors.toMap( + entry -> entry.getKey().split("%")[0], // 只保留%之前的部分 + Map.Entry::getValue + )); + List priceSheetVOList = newMap.entrySet().stream() + .filter(entry -> partCode.startsWith(entry.getKey())) + .flatMap(entry -> entry.getValue().stream()) // 将 List 扁平化为 Stream + .collect(Collectors.toList()); + //匹配成功,保存报价集合 + if (null != priceSheetVOList && !priceSheetVOList.isEmpty()) { + statementVO.setPriceSheetList(priceSheetVOList); + return true; + } + return false; + } + + /** + * 规则:镀层厚度匹配 + * + * @param statementVO + * @return + */ + private boolean rulePlateThickness(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //结算单的镀层厚度维度分匹配报价的物料号, + String plateThickness = statementVO.getPlateThickness(); + if (StringUtils.isEmpty(plateThickness)) { + return false; + } + Map> map = priceSheetList.stream().collect(Collectors.groupingBy(PriceSheetVO::getPrtno)); + //镀层厚度值相等,保存报价集合 + if (map.containsKey(plateThickness)) { + statementVO.setPriceSheetList(map.get(plateThickness)); + return true; + } + return false; + } + + /** + * 规则:阶梯价匹配 + * + * @param statementVO + * @return + */ + private boolean ruleTieredPricing(StatementVO statementVO) { + List priceSheetList = statementVO.getPriceSheetList(); + //如果无报价,结算异常:无报价记录结算结果 + if (null == priceSheetList || priceSheetList.isEmpty()) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + //如果只剩唯一报价,则直接使用 + if (priceSheetList.size() == 1) { + //唯一使用此报价单**结算** + PriceSheetVO priceSheet = priceSheetList.get(0); + BigDecimal unitPrice = new BigDecimal(priceSheet.getPrice()); + BigDecimal qty = new BigDecimal(statementVO.getMakeQty()); + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setUnitPrice(unitPrice); + statementVO.setUnit(priceSheet.getPrtum()); + statementVO.setTotalPrice(unitPrice.multiply(qty)); + statementVO.setMemo("结算中"); + statementVO.setQuotation(priceSheet.getSeqid()); + //使用此报价 + return true; + } + //匹配阶梯价 + //1.只允许有一种阶梯价 + Map> StairPriceSheetMap = priceSheetList.stream().filter(priceSheet -> { + String stairflag = priceSheet.getStairflag(); + return stairflag != null && !stairflag.trim().isEmpty(); + }).collect(Collectors.groupingBy(PriceSheetVO::getStairflag)); + if (StairPriceSheetMap.keySet().size() > 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价类型【%s】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), String.join(", ", StairPriceSheetMap.keySet()))); + return true; + } else if (StairPriceSheetMap.keySet().size() < 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + if (StairPriceSheetMap.keySet().contains("非阶梯价")) { + //2.如果阶梯价是非阶梯价,判断报价是否唯一 + List priceSheetVOS = StairPriceSheetMap.get("非阶梯价"); + if (null == priceSheetVOS || priceSheetVOS.isEmpty()) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName(), "非阶梯价")); + return true; + } else if (null != priceSheetVOS && priceSheetVOS.size() > 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), "非阶梯价")); + return true; + } + //唯一使用此报价单**结算** + PriceSheetVO priceSheet = priceSheetVOS.get(0); + BigDecimal unitPrice = new BigDecimal(priceSheet.getPrice()); + BigDecimal qty = new BigDecimal(statementVO.getMakeQty()); + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setUnitPrice(unitPrice); + statementVO.setUnit(priceSheet.getPrtum()); + statementVO.setTotalPrice(unitPrice.multiply(qty)); + statementVO.setMemo("结算中"); + statementVO.setQuotation(priceSheet.getSeqid()); + return true; + } else if (StairPriceSheetMap.keySet().contains("单批阶梯价(按单件面积)")) { + //3.如果阶梯价是按单件面积,判断报价是否唯一 + List priceSheetVOS = StairPriceSheetMap.get("单批阶梯价(按单件面积)"); + //获取结算单的单件面积,匹配报价里的阶梯上下限 + String ypArea = statementVO.getYpArea(); + if (ypArea != null && ypArea.endsWith(".")) { + ypArea = ypArea.substring(0, ypArea.length() - 1); + } + double ypAreaValue = Double.parseDouble(ypArea); + if (null != priceSheetVOS && priceSheetVOS.size() > 1) { + List priceSheetVOList = priceSheetVOS.stream() + .filter(vo -> { + double lower = Double.parseDouble(vo.getLower()); + double upper = Double.parseDouble(vo.getUpper()); + return ypAreaValue >= lower && ypAreaValue <= upper; + }).collect(Collectors.toList()); + if (null != priceSheetVOList && priceSheetVOList.size() > 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), "单批阶梯价(按单件面积)")); + return true; + } else if (null != priceSheetVOList && priceSheetVOList.size() == 1) { + //唯一使用此报价单**结算** + PriceSheetVO priceSheet = priceSheetVOList.get(0); + BigDecimal unitPrice = new BigDecimal(priceSheet.getPrice()); + BigDecimal qty = new BigDecimal(statementVO.getMakeQty()); + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setUnitPrice(unitPrice); + statementVO.setUnit(priceSheet.getPrtum()); + statementVO.setTotalPrice(unitPrice.multiply(qty)); + statementVO.setMemo("结算中"); + statementVO.setQuotation(priceSheet.getSeqid()); + return true; + } + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName(), "单批阶梯价(按单件面积)")); + return true; + } + return true; + } else if (StairPriceSheetMap.keySet().contains("单批阶梯价(按单批面积)")) { + //4.如果阶梯价是按单批面积,判断报价是否唯一 + List priceSheetVOS = StairPriceSheetMap.get("单批阶梯价(按单批面积)"); + //获取结算单的单件面积,匹配报价里的阶梯上下限 + String totalArea = statementVO.getTotalArea(); + if (totalArea != null && totalArea.endsWith(".")) { + totalArea = totalArea.substring(0, totalArea.length() - 1); + } + double totalAreaValue = Double.parseDouble(totalArea); + if (null != priceSheetVOS && priceSheetVOS.size() > 1) { + List priceSheetVOList = priceSheetVOS.stream() + .filter(vo -> { + double lower = Double.parseDouble(vo.getLower()); + double upper = Double.parseDouble(vo.getUpper()); + return totalAreaValue >= lower && totalAreaValue <= upper; + }).collect(Collectors.toList()); + if (null != priceSheetVOList && priceSheetVOList.size() > 1) { + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配多条报价记录", statementVO.getOcName(), statementVO.getPartName(), "单批阶梯价(按单批面积)")); + return true; + } else if (null != priceSheetVOList && priceSheetVOList.size() == 1) { + //唯一使用此报价单**结算** + PriceSheetVO priceSheet = priceSheetVOList.get(0); + BigDecimal unitPrice = new BigDecimal(priceSheet.getPrice()); + BigDecimal qty = new BigDecimal(statementVO.getMakeQty()); + statementVO.setRosStatus(StatementVO.IN_SETTLEMENT); + statementVO.setUnitPrice(unitPrice); + statementVO.setUnit(priceSheet.getPrtum()); + statementVO.setTotalPrice(unitPrice.multiply(qty)); + statementVO.setMemo("结算中"); + statementVO.setQuotation(priceSheet.getSeqid()); + return true; + } + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价【】匹配无报价记录", statementVO.getOcName(), statementVO.getPartName(), "单批阶梯价(按单批面积)")); + return true; + } + return true; + } else { + //todo:qyl 5.其他阶梯价类型暂不处理,找客户确认 + statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT); + statementVO.setMemo(String.format("外协厂商【%s】,工序内容【%s】,阶梯价匹配无报价记录", statementVO.getOcName(), statementVO.getPartName())); + return true; + } + } + + /** + * 检查是否有涂色相关的数量 + */ + private boolean hasColorCount(StatementVO statementVO) { + return StringUtils.isNotEmpty(statementVO.getTjtNum()) + || StringUtils.isNotEmpty(statementVO.getTsbNum()) + || StringUtils.isNotEmpty(statementVO.getTsdNum()); + } + + /** + * 条件1: prtdesc 匹配 + */ + private boolean matchesCondition1(PriceSheetVO priceSheet, StatementVO statementVO) { + String prtdesc = priceSheet.getPrtdesc(); + String partName = statementVO.getPartName(); + + // 条件: prtdesc 为空 或 与 partName 相等 + return StringUtils.isBlank(prtdesc) || partName.equals(prtdesc); + } + + /** + * 条件2: prtlotno 匹配 + */ + private boolean matchesCondition2(PriceSheetVO priceSheet, StatementVO statementVO) { + String prtlotno = priceSheet.getPrtlotno(); + String prodIdent = statementVO.getProdIdent(); + + // 如果 prtlotno 是 "/",条件满足 + if ("/".equals(prtlotno)) { + return true; + } + + // 按"和"分割,检查前缀 + String[] prefixes = prtlotno.split("和"); + + return Arrays.stream(prefixes) + .map(String::trim) // 去除空格 + .anyMatch(prodIdent::startsWith); + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/PlatingTypeRulesServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/PlatingTypeRulesServiceImpl.java new file mode 100644 index 000000000..8812c9072 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/PlatingTypeRulesServiceImpl.java @@ -0,0 +1,58 @@ +package org.springblade.desk.oem.service.impl; + +import org.springblade.core.tool.api.R; +import org.springblade.desk.oem.pojo.entity.OemProcessEntity; +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesExcel; +import org.springblade.desk.oem.pojo.excel.PlatingTypeRulesImport; +import org.springblade.desk.oem.pojo.vo.PlatingTypeRulesVO; +import org.springblade.desk.oem.mapper.PlatingTypeRulesMapper; +import org.springblade.desk.oem.service.IPlatingTypeRulesService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.core.mp.base.BaseServiceImpl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 外协镀种规则 服务实现类 + * + * @author qyl + * @since 2026-03-03 + */ +@Service +public class PlatingTypeRulesServiceImpl extends BaseServiceImpl implements IPlatingTypeRulesService { + + @Override + public IPage selectPlatingTypeRulesPage(IPage page, PlatingTypeRulesVO mesPlatingTypeRules) { + return page.setRecords(baseMapper.selectPlatingTypeRulesPage(page, mesPlatingTypeRules)); + } + + + @Override + public List exportPlatingTypeRules(Wrapper queryWrapper) { + List mesPlatingTypeRulesList = baseMapper.exportPlatingTypeRules(queryWrapper); + //mesPlatingTypeRulesList.forEach(mesPlatingTypeRules -> { + // mesPlatingTypeRules.setTypeName(DictCache.getValue(DictEnum.YES_NO, PlatingTypeRules.getType())); + //}); + return mesPlatingTypeRulesList; + } + + @Override + public R saveExcelData(List importList) { + List saves = new ArrayList<>(); + importList.forEach(platingTypeRulesImport -> { + PlatingTypeRulesEntity mesPlatingTypeRulesEntity = new PlatingTypeRulesEntity(); + BeanUtils.copyProperties(platingTypeRulesImport, mesPlatingTypeRulesEntity); + mesPlatingTypeRulesEntity.setCreateTime(new Date()); + saves.add(mesPlatingTypeRulesEntity); + }); + baseMapper.insertOrUpdate(saves); + return R.success("操作完成"); + } + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/wrapper/PlatingTypeRulesWrapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/wrapper/PlatingTypeRulesWrapper.java new file mode 100644 index 000000000..73208789d --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/oem/wrapper/PlatingTypeRulesWrapper.java @@ -0,0 +1,35 @@ +package org.springblade.desk.oem.wrapper; + +import org.springblade.core.mp.support.BaseEntityWrapper; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity; +import org.springblade.desk.oem.pojo.vo.PlatingTypeRulesVO; + +import java.util.Objects; + +/** + * 外协镀种规则 包装类,返回视图层所需的字段 + * + * @author qyl + * @since 2026-03-03 + */ +public class PlatingTypeRulesWrapper extends BaseEntityWrapper { + + public static PlatingTypeRulesWrapper build() { + return new PlatingTypeRulesWrapper(); + } + + @Override + public PlatingTypeRulesVO entityVO(PlatingTypeRulesEntity mesPlatingTypeRules) { + PlatingTypeRulesVO mesPlatingTypeRulesVO = Objects.requireNonNull(BeanUtil.copyProperties(mesPlatingTypeRules, PlatingTypeRulesVO.class)); + + //User createUser = UserCache.getUser(mesPlatingTypeRules.getCreateUser()); + //User updateUser = UserCache.getUser(mesPlatingTypeRules.getUpdateUser()); + //mesPlatingTypeRulesVO.setCreateUserName(createUser.getName()); + //mesPlatingTypeRulesVO.setUpdateUserName(updateUser.getName()); + + return mesPlatingTypeRulesVO; + } + + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkOrderRunMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkOrderRunMapper.xml index ddbcb3389..a66a37a4b 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkOrderRunMapper.xml +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkOrderRunMapper.xml @@ -42,6 +42,7 @@ + @@ -78,6 +79,7 @@ two.inventory_qty, two.send_down_time, two.put_store_time, + two.approval_status, tyo.yp_code, tyo.part_code, tyo.part_name, @@ -106,9 +108,9 @@ -- 关联生产订单表 LEFT JOIN MES_YIELD_ORDER tyo ON two.yo_id = tyo.id -- 关联转出班组(只取名称) - LEFT JOIN BA_TEAM_SET out_team ON mwor.out_team = out_team.id + LEFT JOIN BS_TEAM_SET out_team ON mwor.out_team = out_team.id -- 关联转入班组(只取名称) - LEFT JOIN BA_TEAM_SET in_team ON mwor.in_team = in_team.id + LEFT JOIN BS_TEAM_SET in_team ON mwor.in_team = in_team.id -- 关联审批人员(只取名称) LEFT JOIN blade_user approval_user ON mwor.approval_man = approval_user.id -- 关联计划员 @@ -159,8 +161,8 @@ AND dispatcher_user.real_name LIKE CONCAT('%', CONCAT(#{query.dispatcher}, '%')) - AND (ome.code LIKE CONCAT('%', CONCAT(#{query.oemCode}, '%')) - OR ome.oc_name LIKE CONCAT('%', CONCAT(#{query.oemCode}, '%'))) + AND (oem.code LIKE CONCAT('%', CONCAT(#{query.oemCode}, '%')) + OR oem.oc_name LIKE CONCAT('%', CONCAT(#{query.oemCode}, '%'))) AND two.priority = #{query.priority} @@ -169,21 +171,21 @@ AND tyo.release_date >= #{query.planIssuanceTimeStart} - AND tyo.release_date <= #{query.planIssuanceTimeEnd} + AND tyo.release_date < #{query.planIssuanceTimeEnd} + 1 AND two.put_store_time >= #{query.postPlatingStorageTimeStart} - AND two.put_store_time <= #{query.postPlatingStorageTimeEnd} + AND two.put_store_time < #{query.postPlatingStorageTimeEnd}+ 1 AND two.demand_date >= #{query.demandDateStart} - AND two.demand_date <= #{query.demandDateEnd} + AND two.demand_date < #{query.demandDateEnd}+ 1 @@ -226,6 +228,7 @@ + @@ -254,6 +257,7 @@ two.wo_code, two.batch_no, two.inventory_qty, + two.approval_status, tyo.part_code, tyo.part_name, tyo.product_ident, @@ -285,8 +289,8 @@ AND mwor.system_data = #{query.systemData} - - AND two.wo_code LIKE CONCAT('%', CONCAT(#{query.orderCode}, '%')) + + AND two.wo_code LIKE CONCAT('%', CONCAT(#{query.woCode}, '%')) AND tyo.part_code LIKE CONCAT('%', CONCAT(#{query.partCode}, '%')) @@ -302,7 +306,7 @@ AND mwor.create_time >= #{query.startTime} - AND mwor.create_time <= #{query.endTime} + AND mwor.create_time < #{query.endTime} + 1 diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderRunServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderRunServiceImpl.java index df875dc73..9c5ca2596 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderRunServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderRunServiceImpl.java @@ -420,7 +420,7 @@ public class WorkOrderRunServiceImpl extends BaseServiceImpl batchResults = workPlanMapper.insertOrUpdate(workPlans); - // todo 2.在MES更改后同步给ERP + // todo:qyl 2.在MES更改后同步给ERP return null; } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java index 32fb80fe4..25a6f1be4 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java @@ -68,6 +68,7 @@ import org.springframework.transaction.annotation.Transactional; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; +import java.math.BigDecimal; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; @@ -1131,6 +1132,8 @@ public class WorkOrderServiceImpl extends BaseServiceImpl AND a.splycode LIKE concat(concat('%', #{query.ocCode}),'%') + + AND a.splyname LIKE concat(concat('%', #{query.ocName}),'%') + AND a.prtno LIKE concat(concat('%', #{query.partCode}),'%') diff --git a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StOtherReceiptRecordMapper.xml b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StOtherReceiptRecordMapper.xml index 3aeb3c811..fcbb0f619 100644 --- a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StOtherReceiptRecordMapper.xml +++ b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StOtherReceiptRecordMapper.xml @@ -22,6 +22,7 @@ - SELECT DISTINCT u.* - FROM BLADE_USER u - -- 关联角色表,筛选库管员角色 - LEFT JOIN BLADE_ROLE rl - ON TO_NUMBER(u.ROLE_ID) = rl.ID - AND rl.IS_DELETED = 0 - LEFT JOIN ST_USER_RIGHT r - ON u.ID = r.USER_ID - AND r.UR_TYPE = #{urType} - AND r.THE_ID = #{theId} - AND r.IS_DELETED = 0 - WHERE r.ID IS NULL - AND rl.ROLE_ALIAS = '库管员' - AND rl.ID IS NOT NULL - AND u.IS_DELETED = 0 - -- 过滤掉ROLE_ID非数字的记录,避免转换失败 - AND REGEXP_LIKE(u.ROLE_ID, '^[0-9]+$'); + SELECT DISTINCT + u.* + FROM + BLADE_USER u + CROSS JOIN ( + SELECT LEVEL AS lv FROM DUAL CONNECT BY LEVEL <= 100 -- 假设最多100个角色,可调整 + ) lvs + -- 拆分角色ID:只保留当前LEVEL对应的角色ID + LEFT JOIN BLADE_ROLE rl + ON TO_NUMBER(REGEXP_SUBSTR(u.ROLE_ID, '[^,]+', 1, lvs.lv)) = rl.ID + AND rl.IS_DELETED = 0 + AND rl.ROLE_ALIAS = '保管员' + -- 原有的权限关联逻辑 + LEFT JOIN ST_USER_RIGHT r + ON u.ID = r.USER_ID + AND r.UR_TYPE = #{urType} + AND r.THE_ID = #{theId} + AND r.IS_DELETED = 0 + WHERE + -- 核心条件:无指定权限 + r.ID IS NULL + -- 确保用户关联到了库管员角色 + AND rl.ID IS NOT NULL + -- 用户未删除 + AND u.IS_DELETED = 0 + -- 过滤掉拆分后无角色ID的行(避免无效匹配) + AND REGEXP_SUBSTR(u.ROLE_ID, '[^,]+', 1, lvs.lv) IS NOT NULL;