liweidong
liweidong-hj 3 months ago
commit bd4e7695f2
  1. 21
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/ReturnToWarehouseDto.java
  2. 4
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java
  3. 12
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/vo/BsWorkCenterVO.java
  4. 24
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/OemStatementEntity.java
  5. 42
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/entity/PlatingTypeRulesEntity.java
  6. 45
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesExcel.java
  7. 29
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/excel/PlatingTypeRulesImport.java
  8. 2
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemApprovalQuery.java
  9. 30
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/OemSettleAccountsSave.java
  10. 5
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/PriceSheetQuery.java
  11. 4
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/request/StatementQuery.java
  12. 41
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemApprovalVO.java
  13. 6
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemOrderVO.java
  14. 9
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/OemProcessVO.java
  15. 21
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/PlatingTypeRulesVO.java
  16. 34
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/oem/pojo/vo/StatementVO.java
  17. 3
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/vo/ProduceMonitorDsPartVO.java
  18. 100
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/util/PriceMatcher.java
  19. 7
      blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.java
  20. 16
      blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/mapper/BsWorkCenterMapper.xml
  21. 2
      blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/IBsWorkCenterService.java
  22. 5
      blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/BsWorkCenterServiceImpl.java
  23. 21
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java
  24. 17
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java
  25. 18
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IPipelineOrderBoxService.java
  26. 277
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
  27. 123
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IPipelineOrderBoxServiceImpl.java
  28. 6
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/PipelineServiceImpl.java
  29. 36
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java
  30. 21
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemOrderController.java
  31. 11
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/OemStatementController.java
  32. 162
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/controller/PlatingTypeRulesController.java
  33. 8
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemAndAbilityMapper.xml
  34. 64
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/OemStatementMapper.xml
  35. 39
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.java
  36. 33
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/mapper/PlatingTypeRulesMapper.xml
  37. 46
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/IPlatingTypeRulesService.java
  38. 674
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/OemStatementServiceImpl.java
  39. 58
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/service/impl/PlatingTypeRulesServiceImpl.java
  40. 35
      blade-service/blade-desk/src/main/java/org/springblade/desk/oem/wrapper/PlatingTypeRulesWrapper.java
  41. 24
      blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkOrderRunMapper.xml
  42. 2
      blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderRunServiceImpl.java
  43. 23
      blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java
  44. BIN
      blade-service/blade-desk/src/main/resources/Excel/oem/外协镀种规则.xls
  45. 3
      blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpDataOemMapper.xml
  46. 1
      blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StOtherReceiptRecordMapper.xml
  47. 26
      blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StUserRightMapper.xml

@ -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;
}

@ -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 = "输送线终点";
/**

@ -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;
}

@ -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<Short, String> rosStatusMap = new HashMap<>(8);
public static Map<Integer, String> 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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -22,7 +22,7 @@ public class OemApprovalQuery {
* 车间订单号
*/
@Schema(description = "车间订单号")
private String orderCode;
private String woCode;
/**
* 零件号
*/

@ -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<StatementVO> statementList;
}

@ -17,6 +17,11 @@ public class PriceSheetQuery {
*/
@Schema(description = "外协厂商CODE")
private String ocCode;
/**
* 外协厂商名称
*/
@Schema(description = "外协厂商名称")
private String ocName;
/**
* 零件号
*/

@ -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;
}

@ -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<Integer, String> approvalStatusMap = new HashMap<Integer, String>(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);
}
}

@ -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;
}

@ -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();
}
}

@ -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;
}

@ -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<PriceSheetVO> priceSheetList;
}

@ -54,4 +54,7 @@ public class ProduceMonitorDsPartVO {
@Schema(description = "是否印字:1、否,2、单,3、双")
private String isPrint;
@Schema(description = "pdm零件图纸地址")
private String url;
}

@ -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<String> findRemarksByPrice(List<String> remarks, BigDecimal targetPrice) {
if (remarks == null || targetPrice == null) {
return new ArrayList<>();
}
List<String> 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<String> findRemarksByPriceStream(Set<String> 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());
}
}

@ -63,4 +63,11 @@ public interface BsWorkCenterMapper extends BaseMapper<BsWorkCenterEntity> {
List<BsWorkCenterVO> getList();
BsWorkCenterEntity selectBsWorkCenterByWcCode(@Param("wcCode")String wcCode);
/**
* 根据ID集合查询工作中心
* @param ids ID集合
* @return 工作中心列表
*/
List<org.springblade.desk.logistics.pojo.vo.BsWorkCenterVO> selectByIds(@Param("ids") List<Long> ids);
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.desk.dashboard.mapper.BsWorkCenterMapper">
<!-- 根据ID集合查询工作中心 -->
<select id="selectByIds" parameterType="java.util.List" resultType="org.springblade.desk.logistics.pojo.vo.BsWorkCenterVO">
SELECT id, WC_NAME
FROM BS_WORK_CENTER
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

@ -70,4 +70,6 @@ public interface IBsWorkCenterService extends BaseService<BsWorkCenterEntity> {
* @return
*/
BsWorkCenterEntity selectBsWorkCenterByWcCode(String wcCode);
List<org.springblade.desk.logistics.pojo.vo.BsWorkCenterVO> getByIds(List<Long> list);
}

@ -74,4 +74,9 @@ public class BsWorkCenterServiceImpl extends BaseServiceImpl<BsWorkCenterMapper,
return workCenterMapper.selectBsWorkCenterByWcCode(wcCode);
}
@Override
public List<org.springblade.desk.logistics.pojo.vo.BsWorkCenterVO> getByIds(List<Long> list) {
return workCenterMapper.selectByIds(list);
}
}

@ -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<TaskVO> 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();
}
}

@ -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();
}

@ -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);
}

@ -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,6 +83,17 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
RUNNING_STATUSES.add(Task.STATUS_BACK_TO_STORAGE);// 返库状态
}
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最佳实践
*
@ -78,13 +103,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
* @param iStationService 站点服务
* @param iLocationService 库位服务
*/
public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService) {
this.iYieldOrderService = iYieldOrderService;
this.iTaskService = iTaskService;
this.iOrderBindService = iOrderBindService;
this.iStationService = iStationService;
this.iLocationService = iLocationService;
}
/**
* 维护订单配件实际重量
@ -183,59 +202,229 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
}
}
/**
* 箱条码与订单解绑
* 流程参数校验 查询运行中任务 重置站点/库位状态 解绑订单 结束任务
* 释放站点并调用AGV小车接口
* <p>
* 业务场景任务结束后释放指定站点根据终点类型触发不同的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<Task> 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<Task> taskList = iTaskService.list(
new LambdaQueryWrapper<Task>().eq(Task::getBoxBarcode, boxBarcode).in(false,Task::getTaskStatus,RUNNING_STATUSES)
);
/**
* 根据站点编号查询站点信息不存在则抛异常
*/
private Station getStationByCode(String stationCode) {
LambdaQueryWrapper<Station> stationQuery = new LambdaQueryWrapper<Station>()
.eq(Station::getStationCode, stationCode);
List<Station> stationList = iStationService.list(stationQuery);
// 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);
if (stationList == null || stationList.isEmpty()) {
log.warn("站点编号不存在,入参:{}", stationCode);
throw new IllegalArgumentException("输入站点编号不存在");
}
return stationList.get(0);
}
// 3.2 重置库位状态为占用(释放库位)
if (task.getLocationId()!=null&&task.getLocationId()!=0) {
Location location = iLocationService.getById(task.getLocationId());
location.setLocationStatus(STATUS_OCCUPIED);
iLocationService.updateById(location);
/**
* 查询有效任务列表运行中状态不存在则抛异常
*/
private List<Task> getValidTaskList(String stationCode) {
LambdaQueryWrapper<Task> taskQuery = new LambdaQueryWrapper<Task>()
.eq(Task::getBoxBarcode, stationCode)
.in(Task::getTaskStatus, RUNNING_STATUSES); // RUNNING_STATUSES建议抽取为常量
List<Task> taskList = iTaskService.list(taskQuery);
if (taskList == null || taskList.isEmpty()) {
log.warn("箱条码数据异常,站点编号:{}", stationCode);
throw new IllegalArgumentException("箱条码数据异常");
}
return taskList;
}
// 3.3 解绑订单(更新绑定状态为未绑定)
List<OrderBind> orderBindList = iOrderBindService.list(new LambdaQueryWrapper<OrderBind>().eq(OrderBind::getTaskId, task.getId()));
if (!CollectionUtils.isEmpty(orderBindList)) {
for (OrderBind orderBind : orderBindList) {
orderBind.setBindingStatus(STATUS_UNBINDED);
iOrderBindService.updateById(orderBind);
/**
* 校验站点状态必须为空闲
*/
private void checkStationStatus(Station station) {
if (!STATUS_FREE.equals(station.getStationStatus())) {
log.warn("站点被占用,站点编号:{},当前状态:{}", station.getStationCode(), station.getStationStatus());
throw new IllegalArgumentException("该站点正在被使用,请使用其他站点");
}
}
// // 3.4 结束任务(更新任务状态为已完成)
// task.setTaskStatus(STATUS_FINISHED);
// iTaskService.updateById(task);
/**
* 校验终点信息终点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<Task> 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;
}
}
/**
* 处理目标站点场景的AGV调度
*/
private R<?> handleTargetStationScenario(Station targetStation, ReturnToWarehouseDto dto, List<Task> 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;
}
}
/**
* 根据WCID查询空闲的终点站点不存在则抛异常
*/
private Station getFreeStationByWcId(Long wcId) {
LambdaQueryWrapper<Station> endStationQuery = new LambdaQueryWrapper<Station>()
.eq(Station::getWcId, wcId)
.eq(Station::getStationStatus, STATUS_FREE);
List<Station> endStationList = iStationService.list(endStationQuery);
if (endStationList == null || endStationList.isEmpty()) {
log.warn("结束站点异常,WCID:{}", wcId);
throw new IllegalArgumentException("结束站点异常");
}
return endStationList.get(0);
}
/**
* 统一更新站点状态封装重复逻辑
*/
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<Station> stationList = iStationService.list(new LambdaQueryWrapper<Station>().eq(Station::getStationStatus, STATUS_FREE));
ArrayList<BsWorkCenterVO> bsWorkCenterVOList = new ArrayList<>();
BsWorkCenterVO bsWorkCenterVO = new BsWorkCenterVO();
bsWorkCenterVO.setWcName(DROPOFF_CONVEYOR_LINE_NAME);
bsWorkCenterVOList.add(bsWorkCenterVO);
if (!stationList.isEmpty()) {
List<Long> list = stationList.stream().map(Station::getWcId).distinct().collect(Collectors.toList());
List<BsWorkCenterVO> bwList = bsWorkCenterService.getByIds(list);
if (!bwList.isEmpty()) {
bwList.forEach(s->{bsWorkCenterVOList.add(s);});
}
}
return R.data(bsWorkCenterVOList);
}
/**

@ -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<Integer> 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<Task> taskList = iTaskService.list(
new LambdaQueryWrapper<Task>().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<OrderBind> orderBindList = iOrderBindService.list(new LambdaQueryWrapper<OrderBind>().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();
}
}

@ -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);
}

@ -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 目标集合ListSetMap等
* @param <T> 字段值的类型泛型适配任意类型
* @return 存在返回true不存在返回false
* @throws IllegalArgumentException 当目标集合为空或类型不支持时抛出异常
*/
public static <T> 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());
}
}

@ -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<IPage<PriceSheetVO>> priceSheetData(PriceSheetQuery priceSheetQuery, Query query) {
R<Page<PriceSheetVO>> pageR = erpDataOemClient.priceSheetData(priceSheetQuery, query);

@ -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());
}
/**
* 导出数据

@ -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<PlatingTypeRulesVO> 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<IPage<PlatingTypeRulesVO>> page(PlatingTypeRulesVO mesPlatingTypeRules, Query query) {
IPage<PlatingTypeRulesVO> 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<String, Object> mesPlatingTypeRules, BladeUser bladeUser, HttpServletResponse response) {
QueryWrapper<PlatingTypeRulesEntity> 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<PlatingTypeRulesExcel> list = mesPlatingTypeRulesService.exportPlatingTypeRules(queryWrapper);
ExcelUtil.export(response, "外协镀种规则数据" + DateUtil.time(), "外协镀种规则数据表", list, PlatingTypeRulesExcel.class);
}
/**
* 下载Excel模板
*/
@GetMapping("/downloadExcelTemplate")
@ApiOperationSupport(order = 10)
@Operation(summary = "下载Excel模板", description = "")
public ResponseEntity<Resource> 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<PlatingTypeRulesImport> importList = ExcelUtil.read(
file, 0, 1, PlatingTypeRulesImport.class
);
return mesPlatingTypeRulesService.saveExcelData(importList);
}
}

@ -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
<if test="query.oemName != null and query.oemName != ''">
AND oem.oc_name LIKE CONCAT('%', CONCAT(#{query.oemName}, '%'))
</if>
<if test="query.caId != null">
AND pa.id = #{query.caId}
AND ca.id = #{query.caId}
</if>
</select>

@ -20,11 +20,29 @@
<result column="UNIT" property="unit"/>
<result column="QUOTATION" property="quotation"/>
<result column="ROS_STATUS" property="rosStatus"/>
<result column="MEMO" property="memo"/>
</resultMap>
<resultMap id="StatementVOResultMap" type="org.springblade.desk.oem.pojo.vo.StatementVO">
<!-- 基础字段映射 -->
<result column="wp_id" property="wpId"/>
<result column="ID" property="id"/>
<result column="TENANT_ID" property="tenantId"/>
<result column="CREATE_USER" property="createUser"/>
<result column="CREATE_TIME" property="createTime"/>
<result column="CREATE_DEPT" property="createDept"/>
<result column="UPDATE_USER" property="updateUser"/>
<result column="UPDATE_TIME" property="updateTime"/>
<result column="STATUS" property="status"/>
<result column="IS_DELETED" property="isDeleted"/>
<result column="WP_ID" property="wpId"/>
<result column="ROS_THICKNESS" property="rosThickness"/>
<result column="UNIT_PRICE" property="unitPrice"/>
<result column="TOTAL_PRICE" property="totalPrice"/>
<result column="UNIT" property="unit"/>
<result column="QUOTATION" property="quotation"/>
<result column="ROS_STATUS" property="rosStatus"/>
<result column="MEMO" property="memo"/>
<result column="wo_id" property="woId"/>
<result column="oc_id" property="ocId"/>
<result column="os_id" property="osId"/>
@ -44,10 +62,13 @@
<!-- 名称描述字段 -->
<result column="part_name" property="partName"/>
<result column="ps_code" property="psCode"/>
<result column="ps_name" property="psName"/>
<result column="ca_name" property="caName"/>
<result column="oc_code" property="ocCode"/>
<result column="oc_name" property="ocName"/>
<result column="plate" property="plate"/>
<result column="plate_goods_code" property="plateGoodsCode"/>
<!-- 时间与数量字段 -->
<result column="put_store_time" property="putStoreTime"/>
@ -62,11 +83,6 @@
<result column="tsb_num" property="tsbNum"/>
<result column="tsd_num" property="tsdNum"/>
<result column="tjt_num" property="tjtNum"/>
<!-- 结算信息字段 -->
<result column="unit_price" property="unitPrice"/>
<result column="unit" property="unit"/>
<result column="total_price" property="totalPrice"/>
</resultMap>
<select id="selectOemStatementPage" resultMap="StatementVOResultMap">
@ -88,12 +104,16 @@
c.id as OC_ID,
g.id as BOP_ID,
a.id as WP_ID,
h.id,
wm_concat(to_char(h.UNIT_PRICE)) AS UNIT_PRICE,
wm_concat(to_char(h.UNIT)) AS UNIT,
wm_concat(to_char(h.TOTAL_PRICE)) AS TOTAL_PRICE,
wm_concat(to_char(h.QUOTATION)) AS QUOTATION,
wm_concat(to_char(h.ROS_STATUS)) AS ROS_STATUS,
wm_concat(to_char(h.MEMO)) AS MEMO,
MAX( h.UPDATE_TIME) AS UPDATE_TIME,
wm_concat(to_char(NVL(h.ROS_STATUS, 1))) AS ROS_STATUS,
wm_concat(to_char(p.plate_code)) AS plate_code,
wm_concat(to_char(p.plate_goods_code)) AS plateGoodsCode,
c.code as OC_CODE,
a.HOUR_QUOTA,
wm_concat(to_char(a.scrap_qty)) AS scrap_qty,
@ -103,6 +123,8 @@
wm_concat(to_char(p.tsd_num)) AS tsd_num,
wm_concat(to_char(p.tjt_num)) AS tjt_num,
e.yo_code,
b.code AS ps_code,
b.name AS ps_name,
i.ca_name,
wm_concat(to_char(p.part_name)) AS part_name,
wm_concat(to_char(h.ros_thickness)) AS ros_thickness,
@ -122,14 +144,27 @@
/*AND (g.craft_ids like '%'||i.ID||'%' or g.craft_ids is null)
and ((g.bop_name in ('浸保护剂','除镀层','清洗(返修)') and e.po_code not like 'W%') OR g.bop_name not in
('浸保护剂','除镀层','清洗(返修)'))*/
AND ((h.ROS_STATUS IS NOT NULL) OR ( a.ID NOT IN ( SELECT WP_ID FROM MES_OEM_STATEMENT)))
/*AND ((h.ROS_STATUS IS NOT NULL) OR ( a.ID NOT IN ( SELECT WP_ID FROM MES_OEM_STATEMENT)))*/
<choose>
<!-- 查询未结算的记录 -->
<when test="query.rosStatusList != null and query.rosStatusList.contains(&quot;1&quot;)">
AND a.ID NOT IN ( SELECT WP_ID FROM MES_OEM_STATEMENT)
</when>
<!-- 查询已结算状态的记录 -->
<when test="query.rosStatusList != null and query.rosStatusList != ''">
AND h.ROS_STATUS IN
<foreach collection="query.rosStatusList.split(',')" item="status"
open="(" separator="," close=")" index="index">
#{status}
</foreach>
</when>
</choose>
<!-- 动态条件拼接 -->
<if test="query.postPlatingStorageTimeStart != null">
AND d.PUT_STORE_TIME &gt;= #{query.postPlatingStorageTimeStart}
</if>
<if test="query.postPlatingStorageTimeEnd != null">
AND d.PUT_STORE_TIME &lt;= #{query.postPlatingStorageTimeEnd}
AND d.PUT_STORE_TIME &lt; #{query.postPlatingStorageTimeEnd} + 1
</if>
<if test="query.prodIdent != null and query.prodIdent != ''">
AND e.PRODUCT_IDENT = #{query.prodIdent}
@ -158,15 +193,8 @@
#{id}
</foreach>
</if>
<if test="query.rosStatusList != null and query.rosStatusList != ''">
AND h.ROS_STATUS IN
<foreach collection="query.rosStatusList.split(',')" item="status"
open="(" separator="," close=")" index="index">
#{status}
</foreach>
</if>
GROUP BY g.PROCESS_ID, a.ID, c.OC_NAME, c.ID, g.ID, d.ID, d.BATCH_NO, c.CODE, a.HOUR_QUOTA, e.yo_code,
i.ca_name, e.use_dept
i.ca_name, e.use_dept,b.name,b.code,h.id
</select>

@ -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<PlatingTypeRulesEntity> {
/**
* 自定义分页
*
* @param page 分页参数
* @param mesPlatingTypeRules 查询参数
* @return List<PlatingTypeRulesVO>
*/
List<PlatingTypeRulesVO> selectPlatingTypeRulesPage(IPage page, PlatingTypeRulesVO mesPlatingTypeRules);
/**
* 获取导出数据
*
* @param queryWrapper 查询条件
* @return List<PlatingTypeRulesExcel>
*/
List<PlatingTypeRulesExcel> exportPlatingTypeRules(@Param("ew") Wrapper<PlatingTypeRulesEntity> queryWrapper);
}

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.desk.oem.mapper.PlatingTypeRulesMapper">
<!-- 通用查询映射结果 -->
<resultMap id="mesPlatingTypeRulesResultMap" type="org.springblade.desk.oem.pojo.entity.PlatingTypeRulesEntity">
<result column="UPDATE_USER" property="updateUser"/>
<result column="UPDATE_TIME" property="updateTime"/>
<result column="STATUS" property="status"/>
<result column="IS_DELETED" property="isDeleted"/>
<result column="ORDER_PLAT" property="orderPlat"/>
<result column="QUOTATION_PLAT" property="quotationPlat"/>
<result column="ID" property="id"/>
<result column="TENANT_ID" property="tenantId"/>
<result column="CREATE_USER" property="createUser"/>
<result column="CREATE_TIME" property="createTime"/>
<result column="CREATE_DEPT" property="createDept"/>
</resultMap>
<select id="selectPlatingTypeRulesPage" resultMap="mesPlatingTypeRulesResultMap">
select *
from MES_PLATING_TYPE_RULES
where is_deleted = 0
</select>
<select id="exportPlatingTypeRules" resultType="org.springblade.desk.oem.pojo.excel.PlatingTypeRulesExcel">
SELECT *
FROM MES_PLATING_TYPE_RULES ${ew.customSqlSegment}
</select>
</mapper>

@ -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<PlatingTypeRulesEntity> {
/**
* 自定义分页
*
* @param page 分页参数
* @param mesPlatingTypeRules 查询参数
* @return IPage<PlatingTypeRulesVO>
*/
IPage<PlatingTypeRulesVO> selectPlatingTypeRulesPage(IPage<PlatingTypeRulesVO> page, PlatingTypeRulesVO mesPlatingTypeRules);
/**
* 导出数据
*
* @param queryWrapper 查询条件
* @return List<PlatingTypeRulesExcel>
*/
List<PlatingTypeRulesExcel> exportPlatingTypeRules(Wrapper<PlatingTypeRulesEntity> queryWrapper);
/**
* 导入
*
* @param list
* @return
*/
R saveExcelData(List<PlatingTypeRulesImport> list);
}

@ -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<OemStatementMapper,
@Resource
private IErpDataOemClient erpDataOemClient;
@Resource
private PlatingTypeRulesMapper platingTypeRulesMapper;
@Override
public IPage<StatementVO> selectOemStatementPage(IPage<StatementVO> page, StatementQuery mesOemStatement) {
return page.setRecords(baseMapper.selectOemStatementPage(page, mesOemStatement));
@ -55,31 +62,660 @@ public class OemStatementServiceImpl extends BaseServiceImpl<OemStatementMapper,
@Override
public R oemSettleAccounts(List<StatementVO> statementVOS, BigDecimal price, LocalDate putStoreDate) {
//以外协厂商分组的Map<厂家代码, 待结算工序结算单列表>
Map<String, List<StatementVO>> oemAndStatementMap = statementVOS.stream().collect(Collectors.groupingBy(StatementVO::getOemCode));
//1.以外协厂商分组的Map<厂家名称, 待结算工序结算单列表>
Map<String, List<StatementVO>> oemAndStatementMap = statementVOS.stream().collect(Collectors.groupingBy(StatementVO::getOcName));
for (Map.Entry<String, List<StatementVO>> listEntry : oemAndStatementMap.entrySet()) {
//外协厂商下全部需要结算的结算单
List<StatementVO> statementVOList = listEntry.getValue();
//以外协代码,日期查出的全部报价单
String oemCode = listEntry.getKey();
//2.以外协名称,日期查出的全部报价单
String oemName = listEntry.getKey();
List<PriceSheetVO> priceSheetAllList = getPriceSheets(oemName, putStoreDate);
if (priceSheetAllList.isEmpty()) {
//【结算异常】
statementVOList.forEach(statementVO -> {
statementVO.setRosStatus(StatementVO.ERR_SETTLEMENT);
statementVO.setMemo(String.format("外协厂商【%s】匹配无报价记录", oemName));
});
} else {
//工序分组Map<工序, 报价列表>
Map<String, List<PriceSheetVO>> priceSheetMap = priceSheetAllList.stream().collect(Collectors.groupingBy(PriceSheetVO::getGxinfo));
/*statementVOList.forEach(statementVO -> {
List<PriceSheetVO> matchedPriceSheets = MatchTheQuotations(statementVO, priceSheetMap);
if (matchedPriceSheets.isEmpty()) {
return;
}
statementVO.setPriceSheetList(matchedPriceSheets);
});*/
//3.为每个结算单匹配报价集合
statementVOList.forEach(statementVO -> {
List<PriceSheetVO> 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;
}
});
}
//保存
List<OemStatementEntity> 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<PriceSheetVO> getPriceSheets(String oemName, LocalDate putStoreDate) {
PriceSheetQuery query = new PriceSheetQuery();
query.setOcCode(oemCode);
query.setOcName(oemName);
query.setInDateStart(putStoreDate);
query.setInDateEnd(putStoreDate);
R<Page<PriceSheetVO>> pageR = erpDataOemClient.priceSheetData(query, new Query() {{
setSize(99999);
}});
//外协厂商下规定日期内的全部报价单
List<PriceSheetVO> priceSheetVOList = null;
if (pageR != null && pageR.getData() != null && pageR.getData().getRecords() != null && pageR.getData().getRecords().size() > 0) {
priceSheetVOList = pageR.getData().getRecords();
}
statementVOList.forEach(statementVO -> {
});
// R<Page<PriceSheetVO>> 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<PriceSheetVO> MatchTheQuotations(StatementVO statementVO, Map<String, List<PriceSheetVO>> 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<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
//取出匹配车间订单号的报价和无车间订单号的报价
Map<String, List<PriceSheetVO>> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
String plateGoodsCode = statementVO.getPlateGoodsCode();
//判断传入参数的当前金价银价 > 0 && 零件镀层物料编码不为空,则需匹配规则
if (price.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isEmpty(plateGoodsCode)) {
//取出所有备注
Map<String, List<PriceSheetVO>> remarkPriceSheetMap = priceSheetList.stream()
.filter(priceSheet -> {
String remark = priceSheet.getRemark();
return remark != null && !remark.trim().isEmpty();
})
.collect(Collectors.groupingBy(
PriceSheetVO::getRemark,
Collectors.toList()
));
Set<String> 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<PriceSheetVO> priceSheetVOList = remarkPriceSheetMap.entrySet().stream()
.filter(entry -> remarksByPrice.contains(entry.getKey())) // 过滤key在keys中的条目
.flatMap(entry -> entry.getValue().stream()) // 将List<PriceSheetVO>扁平化为PriceSheetVO流
.collect(Collectors.toList());
statementVO.setPriceSheetList(priceSheetVOList);
return false;
}
//结束当前规则匹配,进入下一规则匹配
return false;
}
/**
* 涂色标涂色带涂箭头匹配规则
*
* @param statementVO
* @return
*/
private boolean ruleColor(StatementVO statementVO) {
List<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
//结算单色标色带箭头数量>0,需要匹配报价里色标色带箭头
//如果结算单没有数量,直接返回false进入下个规则
if (!hasColorCount(statementVO)) {
//结束当前规则匹配,进入下一规则匹配
return false;
}
//涂色标、涂色带、涂箭头的报价集合
Map<String, List<PriceSheetVO>> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
//结算单的镀种维度匹配报价的物料号
String plate = statementVO.getPlate();
if (StringUtils.isEmpty(plate)) {
return false;
}
Map<String, List<PriceSheetVO>> map = priceSheetList.stream().collect(Collectors.groupingBy(PriceSheetVO::getPrtno));
//1.精确匹配,完整的镀种
if (map.containsKey(plate)) {
statementVO.setPriceSheetList(map.get(plate));
return true;
}
//2.使用模糊查询。根据订单中的镀种,到镀种映射表中查询对应的代码,再根据代码查找报价,适用于:Ap.Ni15、Ap.Ni20有同一个报价Ap.Ni%Cu%Xn%
LambdaQueryWrapper<PlatingTypeRulesEntity> 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<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
//结算单的零件号维度匹配报价的物料号
String partCode = statementVO.getPartCode();
if (StringUtils.isEmpty(partCode)) {
return false;
}
Map<String, List<PriceSheetVO>> map = priceSheetList.stream().collect(Collectors.groupingBy(PriceSheetVO::getPrtno));
//1.精确匹配,完整的零件号
if (map.containsKey(partCode)) {
statementVO.setPriceSheetList(map.get(partCode));
return true;
}
//2.模糊查询报价单中为一类零件号, 如81E6-%螺母
Map<String, List<PriceSheetVO>> newMap = map.entrySet().stream()
.filter(entry -> entry.getKey().contains("-%"))
.collect(Collectors.toMap(
entry -> entry.getKey().split("%")[0], // 只保留%之前的部分
Map.Entry::getValue
));
List<PriceSheetVO> priceSheetVOList = newMap.entrySet().stream()
.filter(entry -> partCode.startsWith(entry.getKey()))
.flatMap(entry -> entry.getValue().stream()) // 将 List<T> 扁平化为 Stream<T>
.collect(Collectors.toList());
//匹配成功,保存报价集合
if (null != priceSheetVOList && !priceSheetVOList.isEmpty()) {
statementVO.setPriceSheetList(priceSheetVOList);
return true;
}
return false;
}
/**
* 规则镀层厚度匹配
*
* @param statementVO
* @return
*/
private boolean rulePlateThickness(StatementVO statementVO) {
List<PriceSheetVO> priceSheetList = statementVO.getPriceSheetList();
//结算单的镀层厚度维度分匹配报价的物料号,
String plateThickness = statementVO.getPlateThickness();
if (StringUtils.isEmpty(plateThickness)) {
return false;
}
Map<String, List<PriceSheetVO>> 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<PriceSheetVO> 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<String, List<PriceSheetVO>> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> 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<PriceSheetVO> 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);
}
}

@ -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<PlatingTypeRulesMapper, PlatingTypeRulesEntity> implements IPlatingTypeRulesService {
@Override
public IPage<PlatingTypeRulesVO> selectPlatingTypeRulesPage(IPage<PlatingTypeRulesVO> page, PlatingTypeRulesVO mesPlatingTypeRules) {
return page.setRecords(baseMapper.selectPlatingTypeRulesPage(page, mesPlatingTypeRules));
}
@Override
public List<PlatingTypeRulesExcel> exportPlatingTypeRules(Wrapper<PlatingTypeRulesEntity> queryWrapper) {
List<PlatingTypeRulesExcel> mesPlatingTypeRulesList = baseMapper.exportPlatingTypeRules(queryWrapper);
//mesPlatingTypeRulesList.forEach(mesPlatingTypeRules -> {
// mesPlatingTypeRules.setTypeName(DictCache.getValue(DictEnum.YES_NO, PlatingTypeRules.getType()));
//});
return mesPlatingTypeRulesList;
}
@Override
public R saveExcelData(List<PlatingTypeRulesImport> importList) {
List<PlatingTypeRulesEntity> 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("操作完成");
}
}

@ -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<PlatingTypeRulesEntity, PlatingTypeRulesVO> {
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;
}
}

@ -42,6 +42,7 @@
<result column="oem_ode" property="oemCode"/>
<result column="release_date" property="planIssuanceTime"/>
<result column="put_store_time" property="postPlatingStorageTime"/>
<result column="approval_status" property="approvalStatus"/>
<!-- 人员信息字段 -->
<result column="planner_name" property="planner"/>
@ -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}, '%'))
</if>
<if test="query.oemCode != null and query.oemCode != ''">
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}, '%')))
</if>
<if test="query.priority != null">
AND two.priority = #{query.priority}
@ -169,21 +171,21 @@
AND tyo.release_date &gt;= #{query.planIssuanceTimeStart}
</if>
<if test="query.planIssuanceTimeEnd != null">
AND tyo.release_date &lt;= #{query.planIssuanceTimeEnd}
AND tyo.release_date &lt; #{query.planIssuanceTimeEnd} + 1
</if>
<if test="query.postPlatingStorageTimeStart != null">
AND two.put_store_time &gt;= #{query.postPlatingStorageTimeStart}
</if>
<if test="query.postPlatingStorageTimeEnd != null">
AND two.put_store_time &lt;= #{query.postPlatingStorageTimeEnd}
AND two.put_store_time &lt; #{query.postPlatingStorageTimeEnd}+ 1
</if>
<if test="query.demandDateStart != null">
AND two.demand_date &gt;= #{query.demandDateStart}
</if>
<if test="query.demandDateEnd != null">
AND two.demand_date &lt;= #{query.demandDateEnd}
AND two.demand_date &lt; #{query.demandDateEnd}+ 1
</if>
<choose>
<when test='query.orderStatus != null and query.orderStatus != ""'>
@ -226,6 +228,7 @@
<result column="product_ident" property="productIdent"/>
<result column="yp_qty" property="makeQty"/>
<result column="yp_area" property="area"/>
<result column="approval_status" property="approvalStatus"/>
<!-- 人员信息字段 -->
<result column="proposer_name" property="proposer"/>
@ -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 @@
<if test="query.systemData != null and query.systemData != ''">
AND mwor.system_data = #{query.systemData}
</if>
<if test="query.orderCode != null and query.orderCode != ''">
AND two.wo_code LIKE CONCAT('%', CONCAT(#{query.orderCode}, '%'))
<if test="query.woCode != null and query.woCode != ''">
AND two.wo_code LIKE CONCAT('%', CONCAT(#{query.woCode}, '%'))
</if>
<if test="query.partCode != null and query.partCode != ''">
AND tyo.part_code LIKE CONCAT('%', CONCAT(#{query.partCode}, '%'))
@ -302,7 +306,7 @@
AND mwor.create_time &gt;= #{query.startTime}
</if>
<if test="query.endTime != null">
AND mwor.create_time &lt;= #{query.endTime}
AND mwor.create_time &lt; #{query.endTime} + 1
</if>
<choose>
<when test='query.approvalStatus != null and query.approvalStatus != ""'>

@ -420,7 +420,7 @@ public class WorkOrderRunServiceImpl extends BaseServiceImpl<WorkOrderRunMapper,
workPlan.setOcId(ocId);
});
List<BatchResult> batchResults = workPlanMapper.insertOrUpdate(workPlans);
// todo 2.在MES更改后同步给ERP
// todo:qyl 2.在MES更改后同步给ERP
return null;
}

@ -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<WorkOrderMapper, WorkO
// 组装零件信息
BeanUtils.copyProperties(dsPartEntity, dsPartVO);
// todo erp查询pdm零件图纸地址
dsPartVO.setUrl("http://MESLoginUser:MESloginUseradmin@pdm.caoe.com/Windchill/netmarkets/jsp/ext/caoe/mes/export.jsp?oid=");
orderDataVO.setDsPart(dsPartVO);
// 组装工序信息
@ -1384,6 +1387,26 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
}
}
}
// 测试数据
ProduceMonitorFileSlotVO fileSlotVO = new ProduceMonitorFileSlotVO();
List<MesRbFilePreserveDetailEntity> childrenList = new ArrayList<>();
MesRbFilePreserveDetailEntity detailEntity = new MesRbFilePreserveDetailEntity();
fileSlotVO.setRfpsType((short) 1);
fileSlotVO.setInsertIndex("1");
fileSlotVO.setSlotIndex("1");
fileSlotVO.setSlotName("测试槽位001");
detailEntity.setRfpsId(BigDecimal.valueOf(1L));
detailEntity.setDetailName("明细名称1");
detailEntity.setDetailIndex("1");
detailEntity.setAsk("工艺要求1");
detailEntity.setRfpdTime("2026-3-6 18:36:44");
detailEntity.setQualified("合格");
detailEntity.setParamName("参数名称1");
detailEntity.setParamValue("参数值1");
childrenList.add(detailEntity);
fileSlotVO.setChildrenList(childrenList);
dsRbFilePreserveSlotList.add(fileSlotVO);
planDataVO.setDsRbFilePreserveSlotList(dsRbFilePreserveSlotList);
}
}

@ -12,6 +12,9 @@
<if test="query.ocCode != null and query.ocCode != ''">
AND a.splycode LIKE concat(concat('%', #{query.ocCode}),'%')
</if>
<if test="query.ocName != null and query.ocName != ''">
AND a.splyname LIKE concat(concat('%', #{query.ocName}),'%')
</if>
<if test="query.partCode != null and query.partCode != ''">
AND a.prtno LIKE concat(concat('%', #{query.partCode}),'%')
</if>

@ -22,6 +22,7 @@
<select id="selectStOtherReceiptRecordPage" resultType="org.springblade.wms.pojo.vo.StOtherReceiptRecordVO">
-- select * from ST_OTHER_RECEIPT_RECORD where is_deleted = 0
SELECT
t1.id,
t2.sir_code ,
t2.goods_id ,
t3.goods_code ,

@ -19,23 +19,33 @@
</resultMap>
<select id="findNoUserRightByTheId" resultType="org.springblade.system.pojo.entity.User">
SELECT DISTINCT u.*
FROM BLADE_USER u
-- 关联角色表,筛选库管员角色
SELECT DISTINCT
u.*
FROM
BLADE_USER u
CROSS JOIN (
SELECT LEVEL AS lv FROM DUAL CONNECT BY LEVEL &lt;= 100 -- 假设最多100个角色,可调整
) lvs
-- 拆分角色ID:只保留当前LEVEL对应的角色ID
LEFT JOIN BLADE_ROLE rl
ON TO_NUMBER(u.ROLE_ID) = rl.ID
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.ROLE_ALIAS = '库管员'
WHERE
-- 核心条件:无指定权限
r.ID IS NULL
-- 确保用户关联到了库管员角色
AND rl.ID IS NOT NULL
-- 用户未删除
AND u.IS_DELETED = 0
-- 过滤掉ROLE_ID非数字的记录,避免转换失败
AND REGEXP_LIKE(u.ROLE_ID, '^[0-9]+$');
-- 过滤掉拆分后无角色ID的行(避免无效匹配)
AND REGEXP_SUBSTR(u.ROLE_ID, '[^,]+', 1, lvs.lv) IS NOT NULL;
</select>
<select id="findByTheIdAndUrType" resultMap="stUserRightResultMap">

Loading…
Cancel
Save