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