From a422cb5b73799050827251f835ebc53d5757a96b Mon Sep 17 00:00:00 2001
From: 1 <1@123>
Date: 星期六, 24 一月 2026 09:06:21 +0800
Subject: [PATCH] lsh#
---
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/validator/SyncOrderValidator.java | 152 +++++++++++
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java | 8
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java | 274 ++++++++++++++++++--
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java | 287 ++++++++++++++++-----
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/SyncOrderController.java | 14
5 files changed, 623 insertions(+), 112 deletions(-)
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/SyncOrderController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/SyncOrderController.java
index 3061e4b..2042e15 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/SyncOrderController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/SyncOrderController.java
@@ -3,6 +3,7 @@
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.api.controller.erp.params.*;
+import com.vincent.rsf.server.api.entity.validator.SyncOrderValidator;
import com.vincent.rsf.server.api.service.ReceiveMsgService;
import com.vincent.rsf.server.common.annotation.OperationLog;
import com.vincent.rsf.server.common.utils.ExcelUtil;
@@ -164,8 +165,17 @@
if (Objects.isNull(orders) || orders.isEmpty()) {
return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
}
-// return receiveMsgService.syncOrderUpdate(orders);
- return receiveMsgService.syncCheckOrder(orders, getLoginUserId());
+ try {
+ // 涓氬姟楠岃瘉
+ new SyncOrderValidator().validateBatchOrders(orders);
+
+ // 澶勭悊涓氬姟
+ return receiveMsgService.syncCheckOrder(orders, getLoginUserId());
+ } catch (IllegalArgumentException e) {
+ return R.error(e.getMessage());
+ } catch (Exception e) {
+ return R.error(e.getMessage());
+ }
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java
index 168e934..22f2bb7 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java
@@ -1,14 +1,16 @@
package com.vincent.rsf.server.api.controller.erp.params;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.vincent.rsf.framework.common.Cools;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
+import javax.validation.Valid;
+import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@@ -20,127 +22,274 @@
private static final long serialVersionUID = 1L;
- /*
- * 涓氬姟绫诲瀷锛屽緟ERP琛ュ厖锛屼互涓嬩负绀轰緥锛�
- * 鍏ュ簱锛氭敹鏂欓�氱煡鍗曪紙PUR_ReceiveBill锛夈��
- * 閲囪喘鍏ュ簱鍗曪紙STK_InStock锛夈��
- * 閫�鏂欑敵璇峰崟锛圥UR_MRAPP锛夈��
- * 閲囪喘閫�鏂欏崟锛圥UR_MRB锛夈��
- * 閫�璐ч�氱煡鍗曪紙SAL_RETURNNOTICE锛夈��
- * 閿�鍞��璐у崟锛圫AL_RETURNSTOCK锛夈��
- * 鐢熶骇閫�鏂欏崟锛圥RD_ReturnMtrl锛夈��
- * 鐢熶骇鍏ュ簱鍗曪紙PRD_INSTOCK锛�/
- * 鐢熶骇姹囨姤鍗曪紙PRD_MORPT锛夈��
- * 鍏朵粬鍏ュ簱鍗曪紙STK_MISCELLANEOUS锛�
- * 鍑哄簱锛氬彂璐ч�氱煡鍗曪紙SAL_DELIVERYNOTICE锛夈��
- * 閿�鍞嚭搴撳崟锛圫AL_OUTSTOCK锛夈��
- * 鍑哄簱鐢宠鍗曪紙STK_OutStockApply锛夈��
- * 鐢熶骇棰嗘枡鍗曪紙PRD_PickMtrl锛夈��
- * 鐢熶骇琛ユ枡鍗曪紙PRD_FeedMtrl锛夈��
- * 鍏朵粬鍑哄簱鍗曪紙STK_MisDelivery锛夎皟鎷細
- * 璋冩嫧鐢宠鍗曪紙STK_TRANSFERAPPLY锛夈��
- * 鐩存帴璋冩嫧鍗曪紙STK_TransferDirect锛�
- * */
+ /**
+ * 涓氬姟绫诲瀷鏋氫妇
+ */
+ public interface BusinessType {
+ // 鍏ュ簱鍗曟嵁
+ String PUR_RECEIVE_BILL = "PUR_ReceiveBill"; // 鏀舵枡閫氱煡鍗�
+ String STK_IN_STOCK = "STK_InStock"; // 閲囪喘鍏ュ簱鍗�
+ String PUR_MRAPP = "PUR_MRAPP"; // 閫�鏂欑敵璇峰崟
+ String PUR_MRB = "PUR_MRB"; // 閲囪喘閫�鏂欏崟
+ String SAL_RETURNNOTICE = "SAL_RETURNNOTICE"; // 閫�璐ч�氱煡鍗�
+ String SAL_RETURNSTOCK = "SAL_RETURNSTOCK"; // 閿�鍞��璐у崟
+ String PRD_RETURN_MTRL = "PRD_ReturnMtrl"; // 鐢熶骇閫�鏂欏崟 //鎺ラ┏
+ String PRD_INSTOCK = "PRD_INSTOCK"; // 鐢熶骇鍏ュ簱鍗� //鎺ラ┏
+ String PRD_MORPT = "PRD_MORPT"; // 鐢熶骇姹囨姤鍗�
+ String STK_MISCELLANEOUS = "STK_MISCELLANEOUS"; // 鍏朵粬鍏ュ簱鍗�
+ // 鍑哄簱鍗曟嵁
+ String SAL_DELIVERYNOTICE = "SAL_DELIVERYNOTICE"; // 鍙戣揣閫氱煡鍗�
+ String SAL_OUTSTOCK = "SAL_OUTSTOCK"; // 閿�鍞嚭搴撳崟
+ String STK_OUTSTOCK_APPLY = "STK_OutStockApply"; // 鍑哄簱鐢宠鍗�
+ String PRD_PICK_MTRL = "PRD_PickMtrl"; // 鐢熶骇棰嗘枡鍗� //鎺ラ┏
+ String PRD_FEED_MTRL = "PRD_FeedMtrl"; // 鐢熶骇琛ユ枡鍗� //鎺ラ┏
+ String STK_MIS_DELIVERY = "STK_MisDelivery"; // 鍏朵粬鍑哄簱鍗�
+ // 璋冩嫧鍗曟嵁
+ String STK_TRANSFER_APPLY = "STK_TRANSFERAPPLY"; // 璋冩嫧鐢宠鍗�
+ String STK_TRANSFER_DIRECT = "STK_TransferDirect"; // 鐩存帴璋冩嫧鍗�
+ }
- @NotNull(message = "涓氬姟绫诲瀷涓嶈兘涓簄ull")
- @NotEmpty(message = "涓氬姟绫诲瀷涓嶈兘涓虹┖")
- @ApiModelProperty("涓氬姟绫诲瀷")
+ /**
+ * 鍗曟嵁绫诲瀷鏋氫妇
+ */
+ public interface OrderType {
+ String OUT_STOCK = "1"; // 鍑哄簱鍗�
+ String IN_STOCK = "2"; // 鍏ュ簱鍗�
+ String TRANSFER = "3"; // 璋冩嫧鍗�
+ }
+
+ @NotBlank(message = "涓氬姟绫诲瀷涓嶈兘涓虹┖")
+ @Pattern(regexp = "^(PUR_ReceiveBill|STK_InStock|PUR_MRAPP|PUR_MRB|SAL_RETURNNOTICE|SAL_RETURNSTOCK|"
+ + "PRD_ReturnMtrl|PRD_INSTOCK|PRD_MORPT|STK_MISCELLANEOUS|SAL_DELIVERYNOTICE|SAL_OUTSTOCK|"
+ + "STK_OutStockApply|PRD_PickMtrl|PRD_FeedMtrl|STK_MisDelivery|STK_TRANSFERAPPLY|STK_TransferDirect)$",
+ message = "涓氬姟绫诲瀷鏍煎紡涓嶆纭�")
+ @ApiModelProperty(value = "涓氬姟绫诲瀷", required = true, example = "STK_InStock")
private String wkType;
-
- /*
- * 璁㈠崟绫诲瀷锛�1 鍑哄簱鍗曪紱2 鍏ュ簱鍗曪紱3 璋冩嫧鍗曪紱
- * */
-
- @NotNull(message = "鍗曟嵁绫诲瀷涓嶈兘涓簄ull")
- @NotEmpty(message = "鍗曟嵁绫诲瀷涓嶈兘涓虹┖")
- @ApiModelProperty("鍗曟嵁绫诲瀷")
+ @NotBlank(message = "鍗曟嵁绫诲瀷涓嶈兘涓虹┖")
+ @Pattern(regexp = "^[123]$", message = "鍗曟嵁绫诲瀷鍙兘鏄�1(鍑哄簱鍗�)銆�2(鍏ュ簱鍗�)鎴�3(璋冩嫧鍗�)")
+ @ApiModelProperty(value = "鍗曟嵁绫诲瀷: 1-鍑哄簱鍗�, 2-鍏ュ簱鍗�, 3-璋冩嫧鍗�", required = true, example = "2")
private String type;
- @NotNull(message = "鍗曞彿涓嶈兘涓簄ull")
- @NotEmpty(message = "鍗曞彿涓嶈兘涓虹┖")
- @ApiModelProperty("鍗曞彿")
+ @NotBlank(message = "鍗曞彿涓嶈兘涓虹┖")
+ @Size(max = 50, message = "鍗曞彿闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+ @ApiModelProperty(value = "鍗曞彿", required = true, example = "PO202401010001")
private String orderNo;
- @NotNull(message = "鍗曟嵁鍐呯爜涓嶈兘涓簄ull")
- @NotEmpty(message = "鍗曟嵁鍐呯爜涓嶈兘涓虹┖")
- @ApiModelProperty("鍗曟嵁鍐呯爜锛屽敮涓�鏍囪瘑")
+ @NotNull(message = "鍗曟嵁鍐呯爜涓嶈兘涓虹┖")
+ @Positive(message = "鍗曟嵁鍐呯爜蹇呴』鏄鏁存暟")
+ @ApiModelProperty(value = "鍗曟嵁鍐呯爜锛屽敮涓�鏍囪瘑", required = true, example = "100001")
private Long orderInternalCode;
- @NotNull(message = "璁㈠崟ID涓嶈兘涓簄ull")
- @NotEmpty(message = "璁㈠崟ID涓嶈兘涓虹┖")
- @ApiModelProperty("璁㈠崟ID")
+// @NotNull(message = "璁㈠崟ID涓嶈兘涓虹┖")
+// @Positive(message = "璁㈠崟ID蹇呴』鏄鏁存暟")
+// @ApiModelProperty(value = "璁㈠崟ID", required = true, example = "200001")
private Long orderId;
- @NotNull(message = "鏁伴噺涓嶈兘涓簄ull")
- @NotEmpty(message = "鏁伴噺涓嶈兘涓虹┖")
- @ApiModelProperty("鏁伴噺")
+// @NotNull(message = "鏁伴噺涓嶈兘涓虹┖")
+// @DecimalMin(value = "0.0", inclusive = false, message = "鏁伴噺蹇呴』澶т簬0")
+// @ApiModelProperty(value = "鏁伴噺", required = true, example = "100.5")
private Double anfme;
- @ApiModelProperty("瀹㈡埛缂栫爜")
+ @ApiModelProperty(value = "瀹㈡埛缂栫爜", example = "CUST001")
private String customerId;
- @ApiModelProperty("瀹㈡埛鍚嶇О")
+ @ApiModelProperty(value = "瀹㈡埛鍚嶇О", example = "XX绉戞妧鏈夐檺鍏徃")
private String customerName;
- @ApiModelProperty("渚涘簲鍟嗙紪鐮�")
+ @ApiModelProperty(value = "渚涘簲鍟嗙紪鐮�", example = "SUP001")
private String supplierId;
- @ApiModelProperty("渚涘簲鍟嗗悕绉�")
+ @ApiModelProperty(value = "渚涘簲鍟嗗悕绉�", example = "XX渚涘簲鍟�")
private String supplierName;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @ApiModelProperty(value = "鍒拌揪鏃堕棿", example = "2024-01-01 10:00:00")
private Date arrTime;
- @ApiModelProperty("鍒涘缓鏃ユ湡锛屾椂闂存埑锛岀簿纭埌绉�")
+ @NotNull(message = "鍒涘缓鏃ユ湡涓嶈兘涓虹┖")
+ @Positive(message = "鍒涘缓鏃ユ湡蹇呴』鏄鏁存暟")
+ @ApiModelProperty(value = "鍒涘缓鏃ユ湡锛屾椂闂存埑锛岀簿纭埌绉�", required = true, example = "1704067200")
private Long createTime;
- @ApiModelProperty("涓氬姟鏃ユ湡锛屽璐︿娇鐢紝鏃堕棿鎴筹紝绮剧‘鍒扮")
+ @NotNull(message = "涓氬姟鏃ユ湡涓嶈兘涓虹┖")
+ @Positive(message = "涓氬姟鏃ユ湡蹇呴』鏄鏁存暟")
+ @ApiModelProperty(value = "涓氬姟鏃ユ湡锛屽璐︿娇鐢紝鏃堕棿鎴筹紝绮剧‘鍒扮", required = true, example = "1704067200")
private Long businessTime;
- @ApiModelProperty("鍗曟嵁鏄庣粏淇℃伅")
+ @Valid
+ @NotNull(message = "鍗曟嵁鏄庣粏淇℃伅涓嶈兘涓虹┖")
+ @Size(min = 1, message = "鑷冲皯闇�瑕佷竴涓槑缁嗛」")
+ @ApiModelProperty(value = "鍗曟嵁鏄庣粏淇℃伅", required = true)
private List<SyncOrdersItem> orderItems;
- @ApiModelProperty("鏀舵枡/鍙戣揣缁勭粐")
+ @ApiModelProperty(value = "鏀舵枡/鍙戣揣缁勭粐", example = "ORG001")
private String stockOrgId;
- @ApiModelProperty("鏀舵枡/鍙戣揣缁勭粐鍚嶇О")
+ @ApiModelProperty(value = "鏀舵枡/鍙戣揣缁勭粐鍚嶇О", example = "鍙戣揣閮�")
private String stockOrgName;
- @ApiModelProperty("閲囪喘缁勭粐")
+ @ApiModelProperty(value = "閲囪喘缁勭粐", example = "PUR001")
private String purchaseOrgId;
- @ApiModelProperty("閲囪喘缁勭粐鍚嶇О")
+ @ApiModelProperty(value = "閲囪喘缁勭粐鍚嶇О", example = "閲囪喘閮�")
private String purchaseOrgName;
- @ApiModelProperty("閲囪喘鍛�")
+ @ApiModelProperty(value = "閲囪喘鍛�", example = "USER001")
private String purchaseUserId;
- @ApiModelProperty("閲囪喘鍛樺悕绉�")
+ @ApiModelProperty(value = "閲囪喘鍛樺悕绉�", example = "寮犱笁")
private String purchaseUserName;
- @ApiModelProperty("鐢熶骇缁勭粐")
+ @ApiModelProperty(value = "鐢熶骇缁勭粐", example = "PRD001")
private String prdOrgId;
- @ApiModelProperty("鐢熶骇缁勭粐鍚嶇О")
+ @ApiModelProperty(value = "鐢熶骇缁勭粐鍚嶇О", example = "鐢熶骇閮�")
private String prdOrgName;
- @ApiModelProperty("閿�鍞粍缁�")
+ @ApiModelProperty(value = "閿�鍞粍缁�", example = "SALE001")
private String saleOrgId;
- @ApiModelProperty("閿�鍞粍缁囧悕绉�")
+ @ApiModelProperty(value = "閿�鍞粍缁囧悕绉�", example = "閿�鍞儴")
private String saleOrgName;
- @ApiModelProperty("閿�鍞憳")
+ @ApiModelProperty(value = "閿�鍞憳", example = "USER002")
private String saleUserId;
- @ApiModelProperty("閿�鍞憳鍚嶇О")
+ @ApiModelProperty(value = "閿�鍞憳鍚嶇О", example = "鏉庡洓")
private String saleUserName;
- @ApiModelProperty("搴撳瓨鏂瑰悜")
+ @ApiModelProperty(value = "搴撳瓨鏂瑰悜", example = "IN")
private String stockDirect;
- @ApiModelProperty("鍑哄叆搴撴帴椹崇珯鐐癸紝鍑哄簱鏃跺皢鐗╂枡鍑哄簱鍚庤繍杈撹嚦璇ョ珯鐐癸紝鍏ュ簱鏃朵粠璇ョ珯鐐瑰皢鐗╂枡杩愬洖搴撲腑")
+ @ApiModelProperty(value = "鍑哄叆搴撴帴椹崇珯鐐癸紝鍑哄簱鏃跺皢鐗╂枡鍑哄簱鍚庤繍杈撹嚦璇ョ珯鐐癸紝鍏ュ簱鏃朵粠璇ョ珯鐐瑰皢鐗╂枡杩愬洖搴撲腑", example = "STATION001")
private String stationId;
-}
+
+ /**
+ * 鑾峰彇瀹為檯鍒拌揪鏃堕棿
+ * 浼樺厛浣跨敤 arrTime锛屽鏋滀负绌哄垯浠� createTime 杞崲
+ */
+ @JsonIgnore
+ public Date getActualArrTime() {
+ if (this.arrTime != null) {
+ return this.arrTime;
+ }
+ if (this.createTime != null) {
+ return new Date(this.createTime * 1000L);
+ }
+ return null;
+ }
+
+ /**
+ * 鑾峰彇瀹為檯涓氬姟鏃堕棿
+ */
+ @JsonIgnore
+ public Date getActualBusinessTime() {
+ if (this.businessTime != null) {
+ return new Date(this.businessTime * 1000L);
+ }
+ return null;
+ }
+
+ /**
+ * 鑾峰彇瀹為檯鍒涘缓鏃堕棿
+ */
+ @JsonIgnore
+ public Date getActualCreateTime() {
+ if (this.createTime != null) {
+ return new Date(this.createTime * 1000L);
+ }
+ return null;
+ }
+
+ /**
+ * 鏄惁鍏ュ簱鍗�
+ */
+ @JsonIgnore
+ public boolean isInStockOrder() {
+ return OrderType.IN_STOCK.equals(this.type);
+ }
+
+ /**
+ * 鏄惁鍑哄簱鍗�
+ */
+ @JsonIgnore
+ public boolean isOutStockOrder() {
+ return OrderType.OUT_STOCK.equals(this.type);
+ }
+
+ /**
+ * 鏄惁璋冩嫧鍗�
+ */
+ @JsonIgnore
+ public boolean isTransferOrder() {
+ return OrderType.TRANSFER.equals(this.type);
+ }
+
+ /**
+ * 涓氬姟楠岃瘉
+ */
+ public void validateBusiness() {
+// if (isOutStockOrder() && Cools.isEmpty(customerId)) {
+// throw new IllegalArgumentException("鍑哄簱鍗曞繀椤绘寚瀹氬鎴�");
+// }
+//
+// if (isInStockOrder() && Cools.isEmpty(supplierId)) {
+// throw new IllegalArgumentException("鍏ュ簱鍗曞繀椤绘寚瀹氫緵搴斿晢");
+// }
+
+// if (Cools.isEmpty(stationId) && !isTransferOrder()) {
+// throw new IllegalArgumentException("蹇呴』鎸囧畾鎺ラ┏绔欑偣");
+// }
+
+ // 楠岃瘉鏄庣粏鎬绘暟涓庝富鍗曟暟閲忔槸鍚︿竴鑷�
+// if (orderItems != null && anfme != null) {
+// double itemsTotal = orderItems.stream()
+// .mapToDouble(item -> item.getAnfme() != null ? item.getAnfme() : 0.0)
+// .sum();
+//
+// if (Math.abs(itemsTotal - anfme) > 0.001) {
+// throw new IllegalArgumentException(String.format(
+// "涓诲崟鏁伴噺(%.3f)涓庢槑缁嗘�绘暟(%.3f)涓嶄竴鑷�", anfme, itemsTotal));
+// }
+// }
+ }
+
+ /**
+ * 璁$畻鏄庣粏鎬绘暟閲�
+ */
+ @JsonIgnore
+ public Double calculateItemsTotal() {
+ if (orderItems == null || orderItems.isEmpty()) {
+ return 0.0;
+ }
+
+ return orderItems.stream()
+ .mapToDouble(item -> item.getAnfme() != null ? item.getAnfme() : 0.0)
+ .sum();
+ }
+
+ /**
+ * 鑾峰彇鍗曟嵁鎽樿
+ */
+ @JsonIgnore
+ public String getSummary() {
+ return String.format("鍗曟嵁[%s] 绫诲瀷[%s] 涓氬姟绫诲瀷[%s] 鍗曟嵁鍐呯爜[%s]",
+ orderNo, type, wkType, orderInternalCode);
+ }
+
+ /**
+ * 鏄惁鏈夋晥鍗曟嵁
+ */
+ @JsonIgnore
+ public boolean isValid() {
+ return !Cools.isEmpty(orderNo) &&
+ orderInternalCode != null && !Cools.isEmpty(orderInternalCode) &&
+ type != null && !Cools.isEmpty(type) &&
+ wkType != null && !Cools.isEmpty(wkType) &&
+ createTime != null && !Cools.isEmpty(createTime) &&
+ businessTime != null && !Cools.isEmpty(businessTime) &&
+ orderItems != null && !orderItems.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java
index 69fb0ee..073db9c 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java
@@ -1,129 +1,327 @@
package com.vincent.rsf.server.api.controller.erp.params;
-
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.vincent.rsf.framework.common.Cools;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
-import lombok.experimental.Accessors;
import lombok.Data;
+import lombok.experimental.Accessors;
+import javax.validation.constraints.*;
import java.io.Serializable;
+import java.math.BigDecimal;
@Data
@Accessors(chain = true)
-@ApiModel(value = "SyncOrdersParams", description = "鍚屾鐩樼偣鍙傛暟")
+@ApiModel(value = "SyncOrdersItem", description = "鍗曟嵁鏄庣粏鍙傛暟")
public class SyncOrdersItem implements Serializable {
private static final long serialVersionUID = 1L;
- @ApiModelProperty("鐩樼偣鍗曟槑缁咺D")
+ /**
+ * 璐т富绫诲瀷鏋氫妇
+ */
+ public interface OwnerType {
+ String SUPPLIER = "supplier"; // 渚涘簲鍟�
+ String CUSTOMER = "customer"; // 瀹㈡埛
+ String COMPANY = "company"; // 鍏徃
+ String THIRD_PARTY = "third_party"; // 绗笁鏂�
+ }
+
+ @ApiModelProperty(value = "鐩樼偣鍗曟槑缁咺D", example = "1001")
private Long id;
- @ApiModelProperty("鐗╂枡鏍囪瘑")
+ @ApiModelProperty(value = "鐗╂枡鏍囪瘑", example = "2001")
private Long matnrId;
- @ApiModelProperty("鐗╂枡缂栫爜")
+ @NotBlank(message = "鐗╂枡缂栫爜涓嶈兘涓虹┖")
+ @Size(max = 50, message = "鐗╂枡缂栫爜闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+ @ApiModelProperty(value = "鐗╂枡缂栫爜", required = true, example = "MAT001")
private String matnr;
- @ApiModelProperty("鐗╂枡鍚嶇О")
+ @ApiModelProperty(value = "鐗╂枡鍚嶇О", example = "鍘熸潗鏂橝")
private String maktx;
- @ApiModelProperty("瀹㈠崟鍙�")
+ @ApiModelProperty(value = "瀹㈠崟鍙�", example = "CUST20240101001")
private String platOrderCode;
- @ApiModelProperty("骞冲彴鏍囪瘑锛堣鍙凤級")
+ @NotBlank(message = "骞冲彴鏍囪瘑锛堣鍙凤級涓嶈兘涓虹┖")
+ @ApiModelProperty(value = "骞冲彴鏍囪瘑锛堣鍙凤級", required = true, example = "10")
private String platItemId;
- @ApiModelProperty("宸ュ崟鍙�")
+ @ApiModelProperty(value = "宸ュ崟鍙�", example = "WO20240101001")
private String platWorkCode;
- @ApiModelProperty("椤圭洰鍙�")
+ @ApiModelProperty(value = "椤圭洰鍙�", example = "PROJ001")
private String projectCode;
- @ApiModelProperty("瀛楁绱㈠紩")
+ @ApiModelProperty(value = "瀛楁绱㈠紩", example = "ext_001")
private String fieldsIndex;
- @ApiModelProperty("瑙勬牸")
+ @ApiModelProperty(value = "瑙勬牸", example = "10 * 20 * 30")
private String spec;
- @ApiModelProperty("鍨嬪彿")
+ @ApiModelProperty(value = "鍨嬪彿", example = "MODEL-A")
private String model;
- @ApiModelProperty("鏁伴噺")
+ @NotNull(message = "鏁伴噺涓嶈兘涓虹┖")
+ @DecimalMin(value = "0.0", inclusive = false, message = "鏁伴噺蹇呴』澶т簬0")
+ @Digits(integer = 10, fraction = 3, message = "鏁伴噺鏁存暟浣嶄笉瓒呰繃10浣嶏紝灏忔暟浣嶄笉瓒呰繃3浣�")
+ @ApiModelProperty(value = "鏁伴噺", required = true, example = "100.5")
private Double anfme;
- @ApiModelProperty("搴撳瓨鍗曚綅")
+ @ApiModelProperty(value = "搴撳瓨鍗曚綅", example = "涓�")
private String unit;
- @ApiModelProperty("搴撳瓨鎵规")
+ @NotBlank(message = "搴撳瓨鎵规涓嶈兘涓虹┖")
+ @Size(max = 50, message = "搴撳瓨鎵规闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+ @ApiModelProperty(value = "搴撳瓨鎵规", required = true, example = "BATCH20240101")
private String batch;
- @ApiModelProperty("宸叉敹鏁伴噺")
+ @DecimalMin(value = "0.0", message = "宸叉敹鏁伴噺涓嶈兘涓鸿礋鏁�")
+ @ApiModelProperty(value = "宸叉敹鏁伴噺", example = "50.0")
private Double qty;
- @ApiModelProperty("鏉″舰鐮�")
+ @ApiModelProperty(value = "鏉″舰鐮�", example = "6936983800013")
private String barcode;
- @ApiModelProperty("鐜伴噾绁ㄥ彿")
+ @ApiModelProperty(value = "鐜伴噾绁ㄥ彿", example = "CASH001")
private String crushNo;
- @ApiModelProperty("璁″垝璺熻釜鍙�")
+ @NotBlank(message = "璁″垝璺熻釜鍙蜂笉鑳戒负绌�")
+ @Size(max = 50, message = "璁″垝璺熻釜鍙烽暱搴︿笉鑳借秴杩�50涓瓧绗�")
+ @ApiModelProperty(value = "璁″垝璺熻釜鍙�", required = true, example = "PLAN20240101")
private String planNo;
- @ApiModelProperty("琛屽唴鐮侊紝鍞竴鏍囪瘑")
+ @NotBlank(message = "琛屽唴鐮佷笉鑳戒负绌�")
+ @Size(max = 50, message = "琛屽唴鐮侀暱搴︿笉鑳借秴杩�50涓瓧绗�")
+ @ApiModelProperty(value = "琛屽唴鐮侊紝鍞竴鏍囪瘑", required = true, example = "LINE001")
private String lineId;
- @ApiModelProperty("鐗╂枡缂栫爜")
+ @ApiModelProperty(value = "鐗╂枡缂栫爜", example = "MAT001")
private String matNr;
- @ApiModelProperty("鐗╂枡鍚嶇О")
+ @ApiModelProperty(value = "鐗╂枡鍚嶇О", example = "鍘熸潗鏂橝")
private String makTx;
- @ApiModelProperty("瑙勬牸")
+ @ApiModelProperty(value = "瑙勬牸", example = "10 * 20 * 30")
private String specs;
- @ApiModelProperty("鍩烘湰鍗曚綅")
+ @ApiModelProperty(value = "鍩烘湰鍗曚綅", example = "PCS")
private String baseUnitId;
- @ApiModelProperty("鎵樼洏鐮侊紝鍗婃垚鍝�/鎴愬搧鍏ュ簱ERP闇�瑕佷紶锛岄潪鍒橢RP涓嶉渶瑕佷紶")
+ @ApiModelProperty(value = "鎵樼洏鐮侊紝鍗婃垚鍝�/鎴愬搧鍏ュ簱ERP闇�瑕佷紶锛岄潪鍒橢RP涓嶉渶瑕佷紶", example = "PALLET001")
private String palletId;
- @ApiModelProperty("璁′环鍗曚綅")
+ @ApiModelProperty(value = "璁′环鍗曚綅", example = "BOX")
private String priceUnitId;
- @ApiModelProperty("寤鸿鐩爣浠撳簱")
+ @ApiModelProperty(value = "寤鸿鐩爣浠撳簱", example = "WH001")
private String targetWareHouseId;
- @ApiModelProperty("璋冨嚭浠�")
+ @ApiModelProperty(value = "璋冨嚭浠�", example = "WH002")
private String sourceWareHouseId;
- @ApiModelProperty("鍏ュ簱绫诲瀷")
+ @ApiModelProperty(value = "鍏ュ簱绫诲瀷", example = "purchase")
private String inStockType;
- @ApiModelProperty("璐т富绫诲瀷")
+ @NotBlank(message = "璐т富绫诲瀷涓嶈兘涓虹┖")
+ @Pattern(regexp = "^(supplier|customer|company|third_party)$",
+ message = "璐т富绫诲瀷蹇呴』鏄痵upplier銆乧ustomer銆乧ompany鎴杢hird_party")
+ @ApiModelProperty(value = "璐т富绫诲瀷", required = true, example = "company")
private String ownerTypeId;
- @ApiModelProperty("璐т富")
+ @NotBlank(message = "璐т富涓嶈兘涓虹┖")
+ @Size(max = 50, message = "璐т富闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+ @ApiModelProperty(value = "璐т富", required = true, example = "OWNER001")
private String ownerId;
- @ApiModelProperty("璐т富鍚嶇О")
+ @NotBlank(message = "璐т富鍚嶇О涓嶈兘涓虹┖")
+ @Size(max = 100, message = "璐т富鍚嶇О闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+ @ApiModelProperty(value = "璐т富鍚嶇О", required = true, example = "XX鏈夐檺鍏徃")
private String ownerName;
- @ApiModelProperty("淇濈鑰呯被鍨�")
+ @ApiModelProperty(value = "淇濈鑰呯被鍨�", example = "warehouse")
private String keeperTypeId;
- @ApiModelProperty("淇濈鑰�")
+ @ApiModelProperty(value = "淇濈鑰�", example = "KEEPER001")
private String keeperId;
- @ApiModelProperty("淇濈鑰呭悕绉�")
+ @ApiModelProperty(value = "淇濈鑰呭悕绉�", example = "浠撳簱绠$悊閮�")
private String keeperName;
+
+ /**
+ * 鑾峰彇瀹為檯鐨勭墿鏂欑紪鐮�
+ * 浼樺厛浣跨敤 matnr锛屽鏋滀负绌哄垯浣跨敤 matNr
+ */
+ @JsonIgnore
+ public String getActualMatnr() {
+ return !Cools.isEmpty(matnr) ? matnr : matNr;
+ }
+
+ /**
+ * 鑾峰彇瀹為檯鐨勭墿鏂欏悕绉�
+ * 浼樺厛浣跨敤 maktx锛屽鏋滀负绌哄垯浣跨敤 makTx
+ */
+ @JsonIgnore
+ public String getActualMaktx() {
+ return !Cools.isEmpty(maktx) ? maktx : makTx;
+ }
+
+ /**
+ * 鑾峰彇瀹為檯鐨勮鏍�
+ * 浼樺厛浣跨敤 spec锛屽鏋滀负绌哄垯浣跨敤 specs
+ */
+ @JsonIgnore
+ public String getActualSpec() {
+ return !Cools.isEmpty(spec) ? spec : specs;
+ }
+
+ /**
+ * 璁剧疆鐗╂枡缂栫爜锛堜繚鎸佷袱涓瓧娈靛悓姝ワ級
+ */
+ public void setMatnr(String matnr) {
+ this.matnr = matnr;
+ this.matNr = matnr;
+ }
public void setMatNr(String matNr) {
this.matNr = matNr;
this.matnr = matNr;
}
+ /**
+ * 璁剧疆鐗╂枡鍚嶇О锛堜繚鎸佷袱涓瓧娈靛悓姝ワ級
+ */
+ public void setMaktx(String maktx) {
+ this.maktx = maktx;
+ this.makTx = maktx;
+ }
+
public void setMakTx(String makTx) {
this.makTx = makTx;
this.maktx = makTx;
}
-}
+
+ /**
+ * 璁剧疆瑙勬牸锛堜繚鎸佷袱涓瓧娈靛悓姝ワ級
+ */
+ public void setSpec(String spec) {
+ this.spec = spec;
+ this.specs = spec;
+ }
+
+ public void setSpecs(String specs) {
+ this.specs = specs;
+ this.spec = specs;
+ }
+
+ /**
+ * 杞崲涓築igDecimal锛堢簿搴﹁绠椾娇鐢級
+ */
+ @JsonIgnore
+ public BigDecimal getAnfmeAsBigDecimal() {
+ return anfme != null ? BigDecimal.valueOf(anfme) : BigDecimal.ZERO;
+ }
+
+ @JsonIgnore
+ public BigDecimal getQtyAsBigDecimal() {
+ return qty != null ? BigDecimal.valueOf(qty) : BigDecimal.ZERO;
+ }
+
+ /**
+ * 鑾峰彇鍓╀綑鏁伴噺
+ */
+ @JsonIgnore
+ public Double getRemainingQty() {
+ if (anfme == null) {
+ return 0.0;
+ }
+ double currentQty = qty != null ? qty : 0.0;
+ double remaining = anfme - currentQty;
+ return Math.max(0, remaining);
+ }
+
+ /**
+ * 鏄惁宸插畬鎴�
+ */
+ @JsonIgnore
+ public boolean isCompleted() {
+ if (anfme == null) {
+ return false;
+ }
+ double currentQty = qty != null ? qty : 0.0;
+ return currentQty >= anfme;
+ }
+
+ /**
+ * 鑾峰彇瀹屾垚鐧惧垎姣�
+ */
+ @JsonIgnore
+ public int getCompletionPercentage() {
+ if (anfme == null || anfme == 0) {
+ return 0;
+ }
+ double currentQty = qty != null ? qty : 0.0;
+ int percentage = (int) ((currentQty / anfme) * 100);
+ return Math.min(Math.max(percentage, 0), 100);
+ }
+
+ /**
+ * 涓氬姟楠岃瘉
+ */
+ public void validateBusiness(String orderType) {
+ if ("purchase".equals(inStockType) && Cools.isEmpty(palletId)) {
+ throw new IllegalArgumentException("閲囪喘鍏ュ簱鏄庣粏蹇呴』鎻愪緵鎵樼洏鐮�");
+ }
+
+ if ("production".equals(inStockType) && Cools.isEmpty(palletId)) {
+ throw new IllegalArgumentException("鐢熶骇鍏ュ簱鏄庣粏蹇呴』鎻愪緵鎵樼洏鐮�");
+ }
+
+ if (!Cools.isEmpty(targetWareHouseId) && !Cools.isEmpty(sourceWareHouseId)) {
+ if (targetWareHouseId.equals(sourceWareHouseId)) {
+ throw new IllegalArgumentException("鐩爣浠撳簱鍜岃皟鍑轰粨搴撲笉鑳界浉鍚�");
+ }
+ }
+
+ if (qty != null && qty > anfme) {
+ throw new IllegalArgumentException("宸叉敹鏁伴噺涓嶈兘澶т簬璁″垝鏁伴噺");
+ }
+ }
+
+ /**
+ * 鏄惁闇�瑕佹墭鐩樼爜
+ */
+ @JsonIgnore
+ public boolean requiresPallet() {
+ return "purchase".equals(inStockType) ||
+ "production".equals(inStockType) ||
+ "return".equals(inStockType);
+ }
+
+ /**
+ * 鏄惁璋冩嫧鏄庣粏
+ */
+ @JsonIgnore
+ public boolean isTransferItem() {
+ return !Cools.isEmpty(sourceWareHouseId) && !Cools.isEmpty(targetWareHouseId);
+ }
+
+ /**
+ * 鑾峰彇鐗╂枡鍞竴鏍囪瘑
+ */
+ @JsonIgnore
+ public String getMaterialKey() {
+ return String.format("%s_%s_%s", getActualMatnr(), batch, getActualSpec());
+ }
+
+ /**
+ * 鑾峰彇鏄庣粏鎽樿
+ */
+ @JsonIgnore
+ public String getSummary() {
+ return String.format("鐗╂枡[%s] 鎵规[%s] 鏁伴噺[%s/%s]",
+ getActualMatnr(), batch, qty, anfme);
+ }
+}
\ No newline at end of file
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/validator/SyncOrderValidator.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/validator/SyncOrderValidator.java
new file mode 100644
index 0000000..801ce07
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/validator/SyncOrderValidator.java
@@ -0,0 +1,152 @@
+package com.vincent.rsf.server.api.entity.validator;
+
+import com.vincent.rsf.framework.common.Cools;
+import com.vincent.rsf.server.api.controller.erp.params.SyncOrderParams;
+import com.vincent.rsf.server.api.controller.erp.params.SyncOrdersItem;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class SyncOrderValidator {
+
+ /**
+ * 楠岃瘉鍚屾璁㈠崟鍙傛暟
+ */
+ public void validateSyncOrder(SyncOrderParams order) {
+ if (order == null) {
+ throw new IllegalArgumentException("璁㈠崟鍙傛暟涓嶈兘涓虹┖");
+ }
+
+ // 鍩烘湰楠岃瘉
+ if (!order.isValid()) {
+ throw new IllegalArgumentException("璁㈠崟鍙傛暟涓嶅畬鏁�");
+ }
+
+ // 涓氬姟楠岃瘉
+ order.validateBusiness();
+
+ // 楠岃瘉鏄庣粏
+ if (order.getOrderItems() == null || order.getOrderItems().isEmpty()) {
+ throw new IllegalArgumentException("璁㈠崟鏄庣粏涓嶈兘涓虹┖");
+ }
+
+ // 妫�鏌ラ噸澶嶈鍙�
+ Set<String> lineIds = new HashSet<>();
+ for (int i = 0; i < order.getOrderItems().size(); i++) {
+ SyncOrdersItem item = order.getOrderItems().get(i);
+ String prefix = "绗�" + (i + 1) + "涓槑缁�: ";
+
+ if (item == null) {
+ throw new IllegalArgumentException(prefix + "鏄庣粏涓虹┖");
+ }
+
+ // 楠岃瘉琛屽唴鐮�
+ if (Cools.isEmpty(item.getLineId())) {
+ throw new IllegalArgumentException(prefix + "琛屽唴鐮佷笉鑳戒负绌�");
+ }
+
+ // 妫�鏌ラ噸澶�
+ if (!lineIds.add(item.getLineId())) {
+ throw new IllegalArgumentException(prefix + "琛屽唴鐮侀噸澶�: " + item.getLineId());
+ }
+
+ // 涓氬姟楠岃瘉
+ try {
+ item.validateBusiness(order.getType());
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(prefix + e.getMessage());
+ }
+ }
+
+// // 楠岃瘉鏁伴噺涓�鑷存��
+// double itemsTotal = order.calculateItemsTotal();
+// if (Math.abs(itemsTotal - order.getAnfme()) > 0.001) {
+// log.warn("璁㈠崟[{}] 涓诲崟鏁伴噺({})涓庢槑缁嗘�绘暟({})涓嶄竴鑷�",
+// order.getOrderNo(), order.getAnfme(), itemsTotal);
+// }
+ }
+
+ /**
+ * 楠岃瘉鎵规璁㈠崟
+ */
+ public void validateBatchOrders(List<SyncOrderParams> orders) {
+ if (orders == null || orders.isEmpty()) {
+ throw new IllegalArgumentException("璁㈠崟鍒楄〃涓嶈兘涓虹┖");
+ }
+
+ if (orders.size() > 100) {
+ throw new IllegalArgumentException("鎵归噺鍚屾鍗曟鏈�澶氭敮鎸�100涓鍗�");
+ }
+
+ // 妫�鏌ラ噸澶嶈鍗曞彿
+ Set<String> orderNos = new HashSet<>();
+ Set<Long> orderInternalCodes = new HashSet<>();
+
+ for (int i = 0; i < orders.size(); i++) {
+ SyncOrderParams order = orders.get(i);
+ String prefix = "绗�" + (i + 1) + "涓鍗�: ";
+
+ if (order == null) {
+ throw new IllegalArgumentException(prefix + "璁㈠崟涓虹┖");
+ }
+
+ // 楠岃瘉璁㈠崟鍙�
+ if (Cools.isEmpty(order.getOrderNo())) {
+ throw new IllegalArgumentException(prefix + "璁㈠崟鍙蜂笉鑳戒负绌�");
+ }
+
+ if (!orderNos.add(order.getOrderNo())) {
+ throw new IllegalArgumentException(prefix + "璁㈠崟鍙烽噸澶�: " + order.getOrderNo());
+ }
+
+ // 楠岃瘉鍗曟嵁鍐呯爜
+ if (order.getOrderInternalCode() == null) {
+ throw new IllegalArgumentException(prefix + "鍗曟嵁鍐呯爜涓嶈兘涓虹┖");
+ }
+
+ if (!orderInternalCodes.add(order.getOrderInternalCode())) {
+ throw new IllegalArgumentException(prefix + "鍗曟嵁鍐呯爜閲嶅: " + order.getOrderInternalCode());
+ }
+
+ // 楠岃瘉鍗曚釜璁㈠崟
+ try {
+ validateSyncOrder(order);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(prefix + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * 杩囨护鏈夋晥璁㈠崟
+ */
+ public List<SyncOrderParams> filterValidOrders(List<SyncOrderParams> orders) {
+ if (orders == null) {
+ return Collections.emptyList();
+ }
+
+ return orders.stream()
+ .filter(order -> order != null && order.isValid())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 璁$畻鎬绘暟閲�
+ */
+// public double calculateTotalQuantity(List<SyncOrderParams> orders) {
+// if (orders == null || orders.isEmpty()) {
+// return 0.0;
+// }
+//
+// return orders.stream()
+// .mapToDouble(order -> order.getAnfme() != null ? order.getAnfme() : 0.0)
+// .sum();
+// }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
index 4509896..51b12ec 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -14,6 +14,7 @@
import com.vincent.rsf.server.api.controller.erp.params.dto.CheckDiffDto;
import com.vincent.rsf.server.api.controller.erp.params.dto.TransferInfoDto;
import com.vincent.rsf.server.api.controller.erp.params.dto.WkOrderDto;
+import com.vincent.rsf.server.api.utils.TimeConverterUtils;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.manager.controller.dto.LocStockDto;
@@ -448,13 +449,14 @@
.setWkType(one.getValue())
.setAnfme(syncOrder.getAnfme())
.setPoCode(syncOrder.getOrderNo())
- .setWorkQty(0.0)
- .setQty(0.0)
+ .setWorkQty(0.0)//鎵ц鏁伴噺
+ .setQty(0.0)//瀹屾垚鏁伴噺
.setPoId(syncOrder.getOrderInternalCode())
.setCode(ruleCode)
.setArrTime(syncOrder.getArrTime())
.setId(null)
- .setCreateTime(new Date())
+ .setCreateTime(new TimeConverterUtils().timestampToDate(syncOrder.getCreateTime()))
+ .setBusinessTime(new TimeConverterUtils().timestampToDate(syncOrder.getBusinessTime()))
.setUpdateTime(new Date())
.setCreateBy(loginUserId)
.setUpdateBy(loginUserId);
--
Gitblit v1.9.1