啊鑫
2025-05-26 b8b017c64b4b05a596b95406fed7b1af9f4c6ba8
添加srm与U9订单数据的对比
已添加26个文件
已修改4个文件
13697 ■■■■■ 文件已修改
README.md 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
logs/xky_service.log 12203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
logs/xky_service.log.2025-05-21.0.gz 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/config/PurchaseParam.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/config/XkyCommonParam.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/entity/MesRohIn.java 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/entity/MesRohInData.java 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/entity/PurchaseOrderCompare.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/entity/PurchaseOrderDetail.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/mapper/MesRohInDataMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/mapper/MesRohInMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/mapper/PurchaseOrderCompareMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/mapper/PurchaseOrderDetailMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/ApiService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/Impl/MesRohInDataServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/Impl/MesRohInServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/Impl/PurchaseOrderCompareServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/Impl/PurchaseOrderDetailServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/MesRohInDataService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/MesRohInService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/PurchaseOrderCompareService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/PurchaseOrderDetailService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/PurchaseService.java 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/service/XkyService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/gs/xky/task/PurchaseOrderSyncTask.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/MesRohInDataMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/MesRohInMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/PurchaseOrderCompareMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/PurchaseOrderDetailMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/gs/xky/XkyApplicationTests.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,157 @@
# é‡‡è´­è®¢å•管理系统
## é¡¹ç›®æ¦‚è¿°
采购订单管理系统用于管理企业的采购流程,包括采购订单、送货通知、收货等功能。系统主要实现了ERP系统与SRM系统之间的采购数据比对功能,帮助企业及时发现并处理两个系统之间的数据差异。
## æŠ€æœ¯æž¶æž„
- Spring Boot框架
- MyBatis Plus ORM框架
- Oracle数据库
- å‰åŽç«¯åˆ†ç¦»æž¶æž„
## ä¸»è¦åŠŸèƒ½æ¨¡å—
1. é‡‡è´­è®¢å•管理
2. é€è´§é€šçŸ¥ç®¡ç†
3. æ”¶è´§ç®¡ç†
4. é€€è´§ç®¡ç†
5. ä¾›åº”商管理
6. ERP与SRM系统数据比对
## æ ¸å¿ƒæ•°æ®å®žä½“
- **采购订单明细(PurchaseOrderDetail)**: å­˜å‚¨SRM系统采购订单数据
- **ERP采购订单数据(MesRohInData)**: å­˜å‚¨ERP系统采购订单数据
- **采购订单比对结果(PurchaseOrderCompare)**: å­˜å‚¨ä¸¤ç³»ç»Ÿæ•°æ®æ¯”对结果
## æ ¸å¿ƒåŠŸèƒ½å®žçŽ°
### æ•°æ®åŒæ­¥ä¸Žæ¯”对流程
1. ä»ŽSRM系统API获取采购订单明细数据
2. æ ¹æ®å•号和项次查询ERP系统中对应的采购订单数据
3. è®¡ç®—两个系统中的待收数量差异
4. å°†æ¯”对结果保存到数据库
### ä½¿ç”¨æ³¨æ„äº‹é¡¹
- API调用频率不低于2小时
- è¯·æ±‚时间范围不大于24小时
- æ•°æ®ç±»åž‹è½¬æ¢éœ€æ³¨æ„ï¼šERP系统(Long)与SRM系统(Integer)
## æ•°æ®åº“表结构
项目中包含以下主要数据表:
1. `PURCHASE_ORDER_DETAIL` - å­˜å‚¨SRM系统采购订单明细数据
2. `MES_ROH_IN_DATA` - å­˜å‚¨ERP系统采购订单数据
3. `PURCHASE_ORDER_COMPARE` - å­˜å‚¨ERP与SRM系统数据比对结果
### è¡¨ç»“构说明
#### é‡‡è´­è®¢å•明细表(PURCHASE_ORDER_DETAIL)的Oracle表结构
```sql
CREATE TABLE PURCHASE_ORDER_DETAIL
(
    ID                       NUMBER(19) PRIMARY KEY,
    PRODUCT_CODE             VARCHAR2(50),
    PRODUCT_NAME             VARCHAR2(100),
    PRODUCT_SCALE            VARCHAR2(200),
    INNER_VENDOR_CODE        VARCHAR2(50),
    INNER_VENDOR_NAME        VARCHAR2(100),
    PROFIT_CENTER_CODE       VARCHAR2(50),
    PROFIT_CENTER_NAME       VARCHAR2(100),
    PURCHASE_TYPE            NUMBER(2),
    PO_ERP_NO                VARCHAR2(50),
    LINE_NO                  VARCHAR2(50),
    PO_LINE_NO_SHOW          VARCHAR2(50),
    ERP_PURCHASE_DATE        NUMBER(19),
    ORDER_STATUS             VARCHAR2(2),
    PO_LINE_STATUS           NUMBER(2),
    PURCHASE_UNIT_CODE       VARCHAR2(20),
    PURCHASE_UNIT_NAME       VARCHAR2(20),
    TOTAL_ANSWER_QTY         NUMBER(10),
    TOTAL_DELIVERY_QTY       NUMBER(10),
    TOTAL_RECEIVE_QTY        NUMBER(10),
    TOTAL_RETURN_QTY         NUMBER(10),
    PO_WAIT_DELIVERY_QTY     NUMBER(10),
    SYS_WAIT_DELIVERY_QTY    NUMBER(10),
    RETURN_WAIT_DELIVERY_QTY NUMBER(10),
    EXPECTED_DATE            NUMBER(19),
    NOTICE_QTY               NUMBER(10),
    NOTICE_UN_DELIVERY_QTY   NUMBER(10),
    TOTAL_REPORT_FINISH_QTY  NUMBER(10),
    ISSUED_SETS              NUMBER(10),
    RECEIVE_STATUS           NUMBER(2),
    VALID_FLAG               NUMBER(1),
    EXTEND_N01               VARCHAR2(200),
    EXTEND_N02               VARCHAR2(200),
    EXTEND_N03               VARCHAR2(200),
    EXTEND_N04               VARCHAR2(200),
    EXTEND_N05               VARCHAR2(200),
    EXTEND_N06               VARCHAR2(200),
    EXTEND_N07               VARCHAR2(200),
    EXTEND_N08               VARCHAR2(200),
    EXTEND_N09               VARCHAR2(200),
    EXTEND_N10               VARCHAR2(200),
    EXTEND_N11               VARCHAR2(200),
    EXTEND_N12               VARCHAR2(200)
);
```
#### é‡‡è´­è®¢å•比对表(PURCHASE_ORDER_COMPARE)的Oracle表结构
```sql
CREATE TABLE PURCHASE_ORDER_COMPARE
(
    ID                   NUMBER(19) PRIMARY KEY,
    BILL_NO              VARCHAR2(50),
    ORDER_LINE_ID        VARCHAR2(50),
    LINE_NO              VARCHAR2(50),
    ERP_PURCHASE_QTY     NUMBER(10),
    ERP_RECEIVED_QTY     NUMBER(10),
    ERP_WAIT_RECEIVE_QTY NUMBER(10),
    SRM_PURCHASE_QTY     NUMBER(10),
    SRM_RECEIVED_QTY     NUMBER(10),
    SRM_WAIT_RECEIVE_QTY NUMBER(10),
    DIFF_FLAG            NUMBER(1),
    DIFF_QTY             NUMBER(10),
    PRODUCT_CODE         VARCHAR2(50),
    PRODUCT_NAME         VARCHAR2(100),
    CREATE_TIME          DATE,
    UPDATE_TIME          DATE
);
```
### åºåˆ—
用于主键ID生成的序列:
```sql
CREATE SEQUENCE SEQ_PURCHASE_ORDER_DETAIL
    START WITH 1
    INCREMENT BY 1
    NOCACHE
    NOCYCLE;
CREATE SEQUENCE SEQ_PURCHASE_ORDER_COMPARE
    START WITH 1
    INCREMENT BY 1
    NOCACHE
    NOCYCLE;
```
## é¡¹ç›®ç»´æŠ¤
如需修改或添加字段,请在相应的实体类文件中进行修改,并保持与数据库表结构同步。
### æ•°æ®åº“维护
如需修改数据库表结构,请按照以下步骤:
1. ä¿®æ”¹å®žä½“类文件中的字段定义
2. ä¿®æ”¹å¯¹åº”çš„SQL文件中的表结构定义
3. æ‰§è¡ŒSQL语句更新数据库表结构
logs/xky_service.log
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
logs/xky_service.log.2025-05-21.0.gz
Binary files differ
src/main/java/com/gs/xky/config/PurchaseParam.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.gs.xky.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY) // è¿™è¡Œä¼šæŽ’除掉所有值为 null çš„字段
public class PurchaseParam implements Serializable {
    private static final long serialVersionUID = 1L;
    //开始时间对应的毫秒时间戳数值;
    private long startTime;
    //结束时间对应的毫秒时间戳数值;
    private long endTime;
    //对应数据操作公司中,员工档案里“ERP帐户”的值,主要做数据鉴权使用
    private String erpCode;
    //采购类型定义说明(1一般采购, 2委外采购,3多角采购,4费用采购,5固资采购,6境外直送,7境外采购,8平台采购,9VMI采购,10样品采购,11折让订单,12退货订单;13_代送订单);
    private int[] purchaseTypeList;
    //订单状态定义说明(1待供应商答交, 2交期差异待确认, 3退回待供应商答交,4变更确认中,5订单已确认, 6已结案, 7已冻结, 8已留置,9预订单,10撤回答交,11采购方撤回,12作废,13供应商方拒绝,14待发送);
    private int[] orderStatusList;
}
src/main/java/com/gs/xky/config/XkyCommonParam.java
@@ -8,14 +8,14 @@
@Data
@AllArgsConstructor
@NoArgsConstructor
public class XkyCommonParam {
public class XkyCommonParam<T> {
    private ApiCommonParam commonParam;
    private BodyParam body;
    private T body;
    public static XkyCommonParam GetInit() {
    public static <T> XkyCommonParam<T> GetInit() {
        long currentTimeMillis = System.currentTimeMillis();
@@ -31,7 +31,7 @@
        String sign = SignUtils.buildCurrentSign(JSON.toJSONString(apiParam), appSecret);
        apiParam.setSign(sign);
        XkyCommonParam commonParam = new XkyCommonParam();
        XkyCommonParam<T> commonParam = new XkyCommonParam<>();
        commonParam.setCommonParam(apiParam);
        return commonParam;
src/main/java/com/gs/xky/entity/MesRohIn.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,218 @@
package com.gs.xky.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * é‡‡è´­è®¢å•表
 *
 * @TableName MES_ROH_IN
 */
@TableName(value = "MES_ROH_IN")
@Data
public class MesRohIn implements Serializable {
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    /**
     * SEQ_BASEINFO_ID
     */
    @TableId
    private Long id;
    /**
     * é‡‡è´­å•号
     */
    private String billNo;
    /**
     * å•据状态
     */
    private String documentStatus;
    /**
     * å•据类型
     */
    private String documentType;
    /**
     * ä¸šåŠ¡ç±»åž‹
     */
    private String businessType;
    /**
     * é‡‡è´­æ—¥æœŸ
     */
    private Date purchaseDate;
    /**
     * ä¾›åº”商
     */
    private String supplier;
    /**
     * å–业务关闭字段 0==未关闭 1==业务关闭
     */
    private String closeStatus;
    /**
     * é‡‡è´­ç»„织
     */
    private String purchaseOrg;
    /**
     * é‡‡è´­éƒ¨é—¨
     */
    private String purchaseDept;
    /**
     * é‡‡è´­ç»„
     */
    private String purchaseGroup;
    /**
     * æ•°é‡éªŒæ”¶
     */
    private String qtyAcceptance;
    /**
     * é‡‡è´­å‘˜
     */
    private String purchaser;
    /**
     * è´¨é‡è¦æ±‚
     */
    private String qualityReq;
    /**
     * ç»“ç®—æ–¹
     */
    private String settlementParty;
    /**
     * æ”¶æ¬¾æ–¹
     */
    private String paymentParty;
    /**
     * é‚®ç®±
     */
    private String email;
    /**
     * è¿è¾“方式
     */
    private String transportMethod;
    /**
     * å¤‡æ³¨
     */
    private String remarks;
    /**
     * æ²»å…·ä¸¶æ¨¡å…·åŠ å·¥åŠé‡‡è´­
     */
    private String fixtureMoldProcurement;
    /**
     * ä½œåºŸçŠ¶æ€
     */
    private String cancellationStatus;
    /**
     * ä½œåºŸäºº
     */
    private String cancellationPerson;
    /**
     * ä½œåºŸæ—¥æœŸ
     */
    private Date cancellationDate;
    /**
     * åˆ›å»ºäºº
     */
    private String createBy;
    /**
     * åˆ›å»ºæ—¥æœŸ
     */
    private Date createDate;
    /**
     * æœ€åŽä¿®æ”¹æ—¶é—´
     */
    private Date lastupdateDate;
    /**
     * æœ€åŽä¿®æ”¹äºº
     */
    private String lastupdateBy;
    /**
     * å®¡æ ¸äºº
     */
    private String erpCheckBy;
    /**
     * å®¡æ ¸æ—¶é—´
     */
    private String erpCheckDate;
    /**
     * ERP的ID号
     */
    private String ebelnK3id;
    /**
     * å®¡æ ¸æ—¥æœŸ
     */
    private Date checkDate;
    /**
     * å®¡æ ¸äºº
     */
    private String checkBy;
    /**
     * å®¡æ ¸æ ‡è¯†
     */
    private Integer checkFalg;
    /**
     * è‡ªå®šä¹‰å­—段1
     */
    private String remark1;
    /**
     * è‡ªå®šä¹‰å­—段2
     */
    private String remark2;
    /**
     * è‡ªå®šä¹‰å­—段3
     */
    private String remark3;
    /**
     * è‡ªå®šä¹‰å­—段4
     */
    private String remark4;
    /**
     * è‡ªå®šä¹‰å­—段5
     */
    private String remark5;
    /**
     * å˜æ›´åŽŸå› 
     */
    private String changereason;
    /**
     * é¢„计到达时间
     */
    private Date arriveDate;
    /**
     * æ”¶æ–™ç»„织
     */
    private String receiveOrg;
    /**
     * å®¡æ‰¹æ„è§
     */
    private String fWwcText;
    /**
     * æ¥æºç±»åˆ«,0=手工 1=请购单 3=需求接口表 4=采购合同 6=采购订单 7=销售订单
     */
    private String srcDocType;
    /**
     * æ¥æºå•据
     */
    private String srcDoc;
    /**
     * è´¸æ˜“路径
     */
    private String tradePathName;
    /**
     * å§”外类型字段暂未使用,默认值-1
     */
    private String subType;
    /**
     * è¿”工订单 æ˜¯å¦å‹¾é€‰é¡¹ 0==不勾选 1==勾选,默认不勾选
     */
    private Integer isReDo;
    /**
     * é¡¹ç›®é‡‡è´­è´Ÿè´£äºº
     */
    private String privateDescSeg1;
    /**
     * å•据版本
     */
    private String version;
}
src/main/java/com/gs/xky/entity/MesRohInData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,270 @@
package com.gs.xky.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * é‡‡è´­è®¢å•明细表
 *
 * @TableName MES_ROH_IN_DATA
 */
@TableName(value = "MES_ROH_IN_DATA")
@Data
public class MesRohInData implements Serializable {
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    /**
     * SEQ_BASEINFO_ID
     */
    @TableId
    private Long id;
    /**
     * é‡‡è´­å•号
     */
    private String billNo;
    /**
     * é”€å”®è®¢å•号
     */
    private String salesOrderId;
    /**
     * é‡‡è´­è®¢å•行号
     */
    private String orderLineId;
    /**
     * ç‰©æ–™ç¼–码
     */
    private String itemId;
    /**
     * é‡‡è´­å•位
     */
    private String purchaseUnit;
    /**
     * é‡‡è´­æ•°é‡
     */
    private Long purchaseQty;
    /**
     * åº“存单位
     */
    private String inventoryUnit;
    /**
     * è®¡ä»·å•位
     */
    private String pricingUnit;
    /**
     * è®¡ä»·æ•°é‡
     */
    private Long pricingQty;
    /**
     * äº¤è´§æ—¥æœŸ
     */
    private Date deliveryDate;
    /**
     * æœ€æ—©äº¤è´§æ—¥æœŸ
     */
    private Date earliestDeliveryDate;
    /**
     * æœ€æ™šäº¤è´§æ—¥æœŸ
     */
    private Date latestDeliveryDate;
    /**
     * éœ€æ±‚组织
     */
    private String demandOrg;
    /**
     * æ”¶æ–™ç»„织
     */
    private String receivingOrg;
    /**
     * ç»“算组织
     */
    private String settlementOrg;
    /**
     * æ˜¯å¦èµ å“
     */
    private String isGift;
    /**
     * å¤‡æ³¨
     */
    private String remarks;
    /**
     * ä¾›åº”商物料编码
     */
    private String supplierItemCode;
    /**
     * ä¾›åº”商物料名称
     */
    private String supplierItemName;
    /**
     * å§”外订单编号
     */
    private String outsourcingOrderId;
    /**
     * æ‰¹å·
     */
    private String batchNumber;
    /**
     * ä¸šåС关闭  A:正常,B:业务终止
     */
    private String businessClose;
    /**
     * ä¸šåŠ¡å†»ç»“  A:正常,B:业务终止
     */
    private String businessFreeze;
    /**
     * å†»ç»“人
     */
    private String freezer;
    /**
     * å†»ç»“æ—¶é—´
     */
    private Date freezeTime;
    /**
     * ä¸šåŠ¡ç»ˆæ­¢
     */
    private String businessTerminate;
    /**
     * ç»ˆæ­¢äºº
     */
    private String terminator;
    /**
     * ç»ˆæ­¢æ—¶é—´
     */
    private Date terminateTime;
    /**
     * ç´¯è®¡æ”¶æ–™æ•°é‡
     */
    private Long totalReceivedQty;
    /**
     * å‰©ä½™æ”¶æ–™æ•°é‡
     */
    private Long remainingReceivedQty;
    /**
     * ç´¯è®¡å…¥åº“数量
     */
    private Long totalStoredQty;
    /**
     * å‰©ä½™å…¥åº“数量
     */
    private Long remainingStoredQty;
    /**
     * ç´¯è®¡é€€æ–™æ•°é‡
     */
    private Long totalReturnedQty;
    /**
     * æ”¶æ–™å¯é€€æ•°é‡
     */
    private Long returnableReceivedQty;
    /**
     * åº“存可退数量
     */
    private Long returnableStoredQty;
    /**
     * æºå•类型
     */
    private String sourceDocumentType;
    /**
     * æºå•单号
     */
    private String sourceDocumentId;
    /**
     * éœ€æ±‚跟踪号
     */
    private String demandTrackingId;
    /**
     * è®¡åˆ’跟踪号
     */
    private String planTrackingId;
    /**
     * å˜æ›´æ ‡å¿—
     */
    private String changeFlag;
    /**
     * éœ€æ±‚来源
     */
    private String demandSource;
    /**
     * éœ€æ±‚单据编号
     */
    private String demandDocumentId;
    /**
     * éœ€æ±‚单据行号
     */
    private String demandDocumentLineId;
    /**
     * ERP的ID号
     */
    private String ebelnK3id;
    /**
     * è‡ªå®šä¹‰å­—段1
     */
    private String remark1;
    /**
     * è‡ªå®šä¹‰å­—段2
     */
    private String remark2;
    /**
     * è‡ªå®šä¹‰å­—段3
     */
    private String remark3;
    /**
     * è‡ªå®šä¹‰å­—段4
     */
    private String remark4;
    /**
     * è‡ªå®šä¹‰å­—段5
     */
    private String remark5;
    /**
     * ERP头ID
     */
    private String erpId;
    /**
     * é‡‡è´­è®¢å•行号
     */
    private String purchaseOrderLineNumber;
    /**
     * éœ€æ±‚组织
     */
    private String demand;
    /**
     * æ”¶æ–™ç»„织
     */
    private String receiving;
    /**
     * ç»“算组织
     */
    private String settlement;
    /**
     * å·²äº¤è´§æ•°é‡
     */
    private Long cgb014;
    /**
     * éœ€æ±‚部门
     */
    private String demandDept;
    /**
     * æ”¶æ–™éƒ¨é—¨
     */
    private String receivingDept;
    /**
     * é¢„计到货时间
     */
    private Date arriveDate;
    /**
     * é¡¹ç›®ï¼ˆç ”发)
     */
    private String rdProject;
    /**
     * é¡¹ç›®
     */
    private String project;
    /**
     * é¡¹ç›®é‡‡è´­äºº
     */
    private String projectPurchaser;
}
src/main/java/com/gs/xky/entity/PurchaseOrderCompare.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
package com.gs.xky.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * ERP与SRM采购订单数据比对表
 *
 * @TableName PURCHASE_ORDER_COMPARE
 */
@TableName(value = "PURCHASE_ORDER_COMPARE")
@Data
@KeySequence(value = "SEQ_PURCHASE_ORDER_COMPARE", dbType = DbType.ORACLE)
public class PurchaseOrderCompare implements Serializable {
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®ID
     */
    @TableId
    private Long id;
    /**
     * ERP采购单号
     */
    private String billNo;
    /**
     * ERP项次号
     */
    private String orderLineId;
    /**
     * SRM项次唯一ID
     */
    private String lineNo;
    /**
     * ERP采购数量
     */
    private Integer erpPurchaseQty;
    /**
     * ERP实收数量
     */
    private Integer erpReceivedQty;
    /**
     * ERP待收数量
     */
    private Integer erpWaitReceiveQty;
    /**
     * SRM采购数量
     */
    private Integer srmPurchaseQty;
    /**
     * SRM实收数量
     */
    private Integer srmReceivedQty;
    /**
     * SRM待收数量
     */
    private Integer srmWaitReceiveQty;
    /**
     * æ•°é‡å·®å¼‚标识(0:无差异;1:有差异)
     */
    private Integer diffFlag;
    /**
     * å·®å¼‚数量(SRM待收数量 - ERP待收数量)
     */
    private Integer diffQty;
    /**
     * äº§å“ç¼–码
     */
    private String productCode;
    /**
     * äº§å“åç§°
     */
    private String productName;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date createTime;
    /**
     * æ›´æ–°æ—¶é—´
     */
    private Date updateTime;
}
src/main/java/com/gs/xky/entity/PurchaseOrderDetail.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,192 @@
package com.gs.xky.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
/**
 * é‡‡è´­è®¢å•明细表
 *
 * @TableName PURCHASE_ORDER_DETAIL
 */
@TableName(value = "PURCHASE_ORDER_DETAIL")
@Data
@KeySequence(value = "SEQ_PURCHASE_ORDER_DETAIL", dbType = DbType.ORACLE)
public class PurchaseOrderDetail implements Serializable {
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
    /**
     * SEQ_PURCHASE_ORDER_DETAIL
     */
    @TableId
    private Long id;
    /**
     * äº§å“ç¼–码
     */
    private String productCode;
    /**
     * äº§å“åç§°
     */
    private String productName;
    /**
     * äº§å“è§„æ ¼
     */
    private String productScale;
    /**
     * å†…部供应商编码
     */
    private String innerVendorCode;
    /**
     * å†…部供应商名称
     */
    private String innerVendorName;
    /**
     * åˆ©æ¶¦ä¸­å¿ƒç¼–码
     */
    private String profitCenterCode;
    /**
     * åˆ©æ¶¦ä¸­å¿ƒåç§°
     */
    private String profitCenterName;
    /**
     * é‡‡è´­ç±»åž‹(1一般采购, 2委外采购,3多角采购,4费用采购,5固资采购,6境外直送,7境外采购,8平台采购,9VMI采购,10样品采购,11折让订单,12退货订单,13代送订单)
     */
    private Integer purchaseType;
    /**
     * erp单号
     */
    private String poErpNo;
    /**
     * é¡¹æ¬¡å”¯ä¸€ID
     */
    private String lineNo;
    /**
     * é¡µé¢å±•示项次
     */
    private String poLineNoShow;
    /**
     * é‡‡è´­æ—¥æœŸ
     */
    private Long erpPurchaseDate;
    /**
     * è®¢å•状态(1待供应商答交, 2交期差异待确认, 3退回待供应商答交,4变更确认中,5订单已确认, 6已结案, 7已冻结, 8已留置,9预订单,10撤回答交,11采购方撤回,12作废,13供应商方拒绝,14待发送)
     */
    private String orderStatus;
    /**
     * è¡ŒçŠ¶æ€ 0:正常,1:结案,2:留置,3:冻结
     */
    private Integer poLineStatus;
    /**
     * é‡‡è´­å•位编码
     */
    private String purchaseUnitCode;
    /**
     * é‡‡è´­å•位名称
     */
    private String purchaseUnitName;
    /**
     * è®¢å•确认数量
     */
    private Integer totalAnswerQty;
    /**
     * å¹³å°å‡ºè´§é‡
     */
    private Integer totalDeliveryQty;
    /**
     * æ”¶è´§æ•°é‡
     */
    private Integer totalReceiveQty;
    /**
     * é€€è´§æ•°é‡
     */
    private Integer totalReturnQty;
    /**
     * è®¢å•待交数量
     */
    private Integer poWaitDeliveryQty;
    /**
     * è¡¥å•待出货量
     */
    private Integer sysWaitDeliveryQty;
    /**
     * é€€è´§å¾…出数量
     */
    private Integer returnWaitDeliveryQty;
    /**
     * äº¤è´§æ—¥æœŸ
     */
    private Long expectedDate;
    /**
     * é€šçŸ¥äº¤è´§é‡
     */
    private Integer noticeQty;
    /**
     * é€šçŸ¥å¾…交量
     */
    private Integer noticeUnDeliveryQty;
    /**
     * å®Œå·¥æ•°é‡
     */
    private Integer totalReportFinishQty;
    /**
     * å‘料套数
     */
    private Integer issuedSets;
    /**
     * æ”¶è´§çŠ¶æ€ 0:待收货;1:部分收货 2:收货完成
     */
    private Integer receiveStatus;
    /**
     * å¤±æ•ˆå¦ 0:无效;1:有效
     */
    private Integer validFlag;
    /**
     * æ‰©å±•字段1
     */
    private String extendN01;
    /**
     * æ‰©å±•字段2
     */
    private String extendN02;
    /**
     * æ‰©å±•字段3
     */
    private String extendN03;
    /**
     * æ‰©å±•字段4
     */
    private String extendN04;
    /**
     * æ‰©å±•字段5
     */
    private String extendN05;
    /**
     * æ‰©å±•字段6
     */
    private String extendN06;
    /**
     * æ‰©å±•字段7
     */
    private String extendN07;
    /**
     * æ‰©å±•字段8
     */
    private String extendN08;
    /**
     * æ‰©å±•字段9
     */
    private String extendN09;
    /**
     * æ‰©å±•字段10
     */
    private String extendN10;
    /**
     * æ‰©å±•字段11
     */
    private String extendN11;
    /**
     * æ‰©å±•字段12
     */
    private String extendN12;
}
src/main/java/com/gs/xky/mapper/MesRohInDataMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.gs.xky.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gs.xky.entity.MesRohInData;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN_DATA(采购订单明细表)】的数据库操作Mapper
 * @createDate 2025-05-26 15:39:07
 * @Entity com.gs.xky.entity.MesRohInData
 */
public interface MesRohInDataMapper extends BaseMapper<MesRohInData> {
}
src/main/java/com/gs/xky/mapper/MesRohInMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.gs.xky.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gs.xky.entity.MesRohIn;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN(采购订单表)】的数据库操作Mapper
 * @createDate 2025-05-26 15:39:01
 * @Entity com.gs.xky.entity.MesRohIn
 */
public interface MesRohInMapper extends BaseMapper<MesRohIn> {
}
src/main/java/com/gs/xky/mapper/PurchaseOrderCompareMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.gs.xky.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gs.xky.entity.PurchaseOrderCompare;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€PURCHASE_ORDER_COMPARE(ERP与SRM采购订单数据比对表)】的数据库操作Mapper
 * @createDate 2025-05-26 19:18:17
 * @Entity generator.domain.PurchaseOrderCompare
 */
public interface PurchaseOrderCompareMapper extends BaseMapper<PurchaseOrderCompare> {
}
src/main/java/com/gs/xky/mapper/PurchaseOrderDetailMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
package com.gs.xky.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gs.xky.entity.PurchaseOrderDetail;
/**
 * é‡‡è´­è®¢å•明细表Mapper接口
 */
public interface PurchaseOrderDetailMapper extends BaseMapper<PurchaseOrderDetail> {
}
src/main/java/com/gs/xky/service/ApiService.java
@@ -33,7 +33,7 @@
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }
    public <T> ApiResponse<T> sendListRequest(XkyCommonParam requestBody, Class<T> responseType, String url) throws IOException {
    public <T, B> ApiResponse<T> sendListRequest(XkyCommonParam<B> requestBody, Class<T> responseType, String url) throws IOException {
        // è®¾ç½®è¯·æ±‚体的媒体类型为 application/json
        MediaType mediaType = MediaType.parse("application/json");
src/main/java/com/gs/xky/service/Impl/MesRohInDataServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.gs.xky.service.Impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gs.xky.entity.MesRohInData;
import com.gs.xky.mapper.MesRohInDataMapper;
import com.gs.xky.service.MesRohInDataService;
import org.springframework.stereotype.Service;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN_DATA(采购订单明细表)】的数据库操作Service实现
 * @createDate 2025-05-26 15:39:07
 */
@Service
public class MesRohInDataServiceImpl extends ServiceImpl<MesRohInDataMapper, MesRohInData>
        implements MesRohInDataService {
}
src/main/java/com/gs/xky/service/Impl/MesRohInServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.gs.xky.service.Impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gs.xky.entity.MesRohIn;
import com.gs.xky.mapper.MesRohInMapper;
import com.gs.xky.service.MesRohInService;
import org.springframework.stereotype.Service;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN(采购订单表)】的数据库操作Service实现
 * @createDate 2025-05-26 15:39:01
 */
@Service
public class MesRohInServiceImpl extends ServiceImpl<MesRohInMapper, MesRohIn>
        implements MesRohInService {
}
src/main/java/com/gs/xky/service/Impl/PurchaseOrderCompareServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.gs.xky.service.Impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gs.xky.entity.PurchaseOrderCompare;
import com.gs.xky.mapper.PurchaseOrderCompareMapper;
import com.gs.xky.service.PurchaseOrderCompareService;
import org.springframework.stereotype.Service;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€PURCHASE_ORDER_COMPARE(ERP与SRM采购订单数据比对表)】的数据库操作Service实现
 * @createDate 2025-05-26 19:18:17
 */
@Service
public class PurchaseOrderCompareServiceImpl extends ServiceImpl<PurchaseOrderCompareMapper, PurchaseOrderCompare>
        implements PurchaseOrderCompareService {
}
src/main/java/com/gs/xky/service/Impl/PurchaseOrderDetailServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.gs.xky.service.Impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gs.xky.entity.PurchaseOrderDetail;
import com.gs.xky.mapper.PurchaseOrderDetailMapper;
import com.gs.xky.service.PurchaseOrderDetailService;
import org.springframework.stereotype.Service;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€PURCHASE_ORDER_DETAIL(采购订单明细表)】的数据库操作Service实现
 * @createDate 2025-05-26 16:49:51
 */
@Service
public class PurchaseOrderDetailServiceImpl extends ServiceImpl<PurchaseOrderDetailMapper, PurchaseOrderDetail>
        implements PurchaseOrderDetailService {
}
src/main/java/com/gs/xky/service/MesRohInDataService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.gs.xky.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gs.xky.entity.MesRohInData;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN_DATA(采购订单明细表)】的数据库操作Service
 * @createDate 2025-05-26 15:39:07
 */
public interface MesRohInDataService extends IService<MesRohInData> {
}
src/main/java/com/gs/xky/service/MesRohInService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.gs.xky.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gs.xky.entity.MesRohIn;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€MES_ROH_IN(采购订单表)】的数据库操作Service
 * @createDate 2025-05-26 15:39:01
 */
public interface MesRohInService extends IService<MesRohIn> {
}
src/main/java/com/gs/xky/service/PurchaseOrderCompareService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.gs.xky.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gs.xky.entity.PurchaseOrderCompare;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€PURCHASE_ORDER_COMPARE(ERP与SRM采购订单数据比对表)】的数据库操作Service
 * @createDate 2025-05-26 19:18:17
 */
public interface PurchaseOrderCompareService extends IService<PurchaseOrderCompare> {
}
src/main/java/com/gs/xky/service/PurchaseOrderDetailService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.gs.xky.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gs.xky.entity.PurchaseOrderDetail;
/**
 * @author 28567
 * @description é’ˆå¯¹è¡¨ã€PURCHASE_ORDER_DETAIL(采购订单明细表)】的数据库操作Service
 * @createDate 2025-05-26 16:49:51
 */
public interface PurchaseOrderDetailService extends IService<PurchaseOrderDetail> {
}
src/main/java/com/gs/xky/service/PurchaseService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,246 @@
package com.gs.xky.service;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gs.xky.config.ApiResponse;
import com.gs.xky.config.DataAcquisitionConfiguration;
import com.gs.xky.config.PurchaseParam;
import com.gs.xky.config.XkyCommonParam;
import com.gs.xky.entity.MesRohInData;
import com.gs.xky.entity.PurchaseOrderCompare;
import com.gs.xky.entity.PurchaseOrderDetail;
import com.gs.xky.mapper.PurchaseOrderCompareMapper;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.Date;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class PurchaseService {
    private static final Logger log = LoggerFactory.getLogger(PurchaseService.class);
    private final ApiService apiService;
    private final MesRohInDataService mesRohInDataService;
    private final PurchaseOrderDetailService purchaseOrderDetailService;
    private final PurchaseOrderCompareMapper purchaseOrderCompareMapper;
    /**
     * åŒæ­¥é‡‡è´­è®¢å•明细数据
     * ä»Žç¬¬ä¸‰æ–¹æŽ¥å£èŽ·å–é‡‡è´­è®¢å•æ˜Žç»†æ•°æ®å¹¶ä¿å­˜åˆ°æœ¬åœ°æ•°æ®åº“
     * æ³¨æ„ï¼šè¯¥æŽ¥å£æœ‰ä»¥ä¸‹é™åˆ¶ï¼š
     * 1. è®¿é—®é¢‘率不能低于2小时
     * 2. ä¸€æ¬¡è¯·æ±‚中时间范围不能大于24小时
     *
     * @throws IOException æŽ¥å£è°ƒç”¨å¼‚常
     */
    public void syncPurchaseOrderDetails() throws IOException {
        long currentTimeMillis = System.currentTimeMillis();
        // é™åˆ¶è¯·æ±‚时间范围为24小时
        long startDate = currentTimeMillis - (24 * 60 * 60 * 1000L);
        XkyCommonParam<PurchaseParam> param = XkyCommonParam.GetInit();
        PurchaseParam bodyParam = new PurchaseParam();
        bodyParam.setStartTime(startDate);
        bodyParam.setEndTime(currentTimeMillis);
        bodyParam.setErpCode(DataAcquisitionConfiguration.TEST_ERP_CODE);
        // æŸ¥è¯¢æ‰€æœ‰çŠ¶æ€çš„è®¢å•
//        bodyParam.setOrderStatusList(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14});
        bodyParam.setPurchaseTypeList(new int[]{1});
        param.setBody(bodyParam);
        log.info("【syncPurchaseOrderDetails】开始同步采购订单数据,时间范围:{} è‡³ {}", startDate, currentTimeMillis);
        // è°ƒç”¨é‡‡è´­è®¢å•明细接口
        ApiResponse<PurchaseOrderDetail> response = apiService.sendListRequest(
                param,
                PurchaseOrderDetail.class,
                "https://openapi.xiekeyun.com/purchase/report/list.json"
        );
        List<PurchaseOrderDetail> orderDetails = response.getDataList();
        if (CollUtil.isEmpty(orderDetails)) {
            log.info("【syncPurchaseOrderDetails】返回列表为空,跳过处理");
            return;
        }
        log.info("【syncPurchaseOrderDetails】获取到{}条采购订单数据", orderDetails.size());
        // å¤„理采购订单明细数据
        orderDetails.forEach(detail -> {
            try {
                // æ ¹æ®æœ‰æ•ˆæ ‡å¿—和订单状态处理不同的业务逻辑
                if (detail.getValidFlag() != null && detail.getValidFlag() == 0) {
                    log.info("【syncPurchaseOrderDetails】无效订单,跳过处理: {}", detail.getPoErpNo());
                    return;
                }
                // èŽ·å–é¡¹æ¬¡å‰é¢çš„ç¼–å·éƒ¨åˆ†
                String linePrefix = extractLinePrefix(detail.getLineNo());
                log.info("【syncPurchaseOrderDetails】项次前缀: {}", linePrefix);
                // æŸ¥è¯¢ERP系统中对应的采购订单数据
                LambdaQueryWrapper<MesRohInData> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(MesRohInData::getBillNo, detail.getPoErpNo())
                        .eq(MesRohInData::getOrderLineId, linePrefix);
                // èŽ·å–ERP数据
                MesRohInData erpData = mesRohInDataService.getOne(wrapper, false);
                if (erpData == null) {
                    log.info("【syncPurchaseOrderDetails】未找到对应的ERP数据,订单号: {}, é¡¹æ¬¡: {}",
                            detail.getPoErpNo(), linePrefix);
                    // åˆ›å»ºä¸€ä¸ªåŒ…含"暂无数据"值的比对记录
                    savePurchaseOrderCompare(detail, null);
                } else {
                    // è®°å½•比对结果
                    savePurchaseOrderCompare(detail, erpData);
                }
                // ä¿å­˜SRM采购订单明细
                savePurchaseOrderDetail(detail);
            } catch (Exception e) {
                log.error("【syncPurchaseOrderDetails å¤„理异常】订单号: {}, é¡¹æ¬¡: {}, å¼‚常: {}",
                        detail.getPoErpNo(), detail.getLineNo(), e.getMessage(), e);
                throw new RuntimeException(e);
            }
        });
    }
    /**
     * ä»ŽlineNo中提取前缀部分
     * ä¾‹å¦‚:从"10-1"中提取出"10"
     *
     * @param lineNo é¡¹æ¬¡ç¼–号,格式如"10-1"
     * @return é¡¹æ¬¡å‰ç¼€ï¼Œå¦‚"10"
     */
    private String extractLinePrefix(String lineNo) {
        if (lineNo == null || lineNo.isEmpty()) {
            return "";
        }
        // ä½¿ç”¨"-"分割字符串
        String[] parts = lineNo.split("-");
        if (parts.length > 0) {
            return parts[0]; // è¿”回第一部分
        }
        // å¦‚果没有"-",则返回原字符串
        return lineNo;
    }
    /**
     * ä¿å­˜ERP与SRM采购订单数据比对结果
     *
     * @param detail  SRM采购订单明细
     * @param erpData ERP采购订单数据(可能为null)
     */
    private void savePurchaseOrderCompare(PurchaseOrderDetail detail, MesRohInData erpData) {
        String linePrefix = extractLinePrefix(detail.getLineNo());
        // æŸ¥è¯¢æ˜¯å¦å·²å­˜åœ¨æ¯”对记录
        LambdaQueryWrapper<PurchaseOrderCompare> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PurchaseOrderCompare::getBillNo, detail.getPoErpNo())
                .eq(PurchaseOrderCompare::getLineNo, detail.getLineNo());
        PurchaseOrderCompare compareData = purchaseOrderCompareMapper.selectOne(wrapper);
        if (compareData == null) {
            // åˆ›å»ºæ–°çš„æ¯”对记录
            compareData = new PurchaseOrderCompare();
            compareData.setBillNo(detail.getPoErpNo());
            compareData.setOrderLineId(linePrefix);
            compareData.setLineNo(detail.getLineNo());
            compareData.setProductCode(detail.getProductCode());
            compareData.setProductName(detail.getProductName());
            compareData.setCreateTime(new Date());
        }
        // è®¡ç®—SRM待收数量
        Integer srmPurchaseQty = detail.getTotalAnswerQty();
        Integer srmReceivedQty = detail.getTotalReceiveQty();
        Integer srmWaitReceiveQty = srmPurchaseQty - srmReceivedQty;
        // è®¾ç½®SRM数据
        compareData.setSrmPurchaseQty(srmPurchaseQty);
        compareData.setSrmReceivedQty(srmReceivedQty);
        compareData.setSrmWaitReceiveQty(srmWaitReceiveQty);
        // è®¾ç½®ERP数据和差异
        if (erpData == null) {
            // ERP系统中没有数据,设置为0
            compareData.setErpPurchaseQty(0);
            compareData.setErpReceivedQty(0);
            compareData.setErpWaitReceiveQty(0);
            compareData.setDiffFlag(1); // æœ‰å·®å¼‚
            compareData.setDiffQty(srmWaitReceiveQty); // å·®å¼‚数量为SRM待收数量
        } else {
            // è®¡ç®—ERP待收数量
            Long erpPurchaseQty = erpData.getPurchaseQty();
            Long erpReceivedQty = erpData.getTotalReceivedQty();
            Long erpWaitReceiveQty = erpPurchaseQty - erpReceivedQty;
            // è®¡ç®—差异
            Long diffQty = srmWaitReceiveQty.longValue() - erpWaitReceiveQty;
//            Integer diffFlag = (diffQty > 0) ? 1 : 0;
            Integer diffFlag = srmWaitReceiveQty.longValue() != erpWaitReceiveQty ? 1 : 0;
            // è®¾ç½®ERP数据
            compareData.setErpPurchaseQty(erpPurchaseQty.intValue());
            compareData.setErpReceivedQty(erpReceivedQty.intValue());
            compareData.setErpWaitReceiveQty(erpWaitReceiveQty.intValue());
            compareData.setDiffFlag(diffFlag);
            compareData.setDiffQty(diffQty.intValue());
        }
        compareData.setUpdateTime(new Date());
        // ä¿å­˜æˆ–更新比对记录
        boolean result;
        if (compareData.getId() == null) {
            result = purchaseOrderCompareMapper.insert(compareData) > 0;
            if (result) {
                log.info("【savePurchaseOrderCompare】新增数据比对记录: è®¢å•号:{}, é¡¹æ¬¡:{}, å·®å¼‚标识:{}, å·®å¼‚数量:{}",
                        detail.getPoErpNo(), detail.getLineNo(), compareData.getDiffFlag(), compareData.getDiffQty());
            } else {
                log.error("【savePurchaseOrderCompare】新增数据比对记录失败: è®¢å•号:{}, é¡¹æ¬¡:{}",
                        detail.getPoErpNo(), detail.getLineNo());
            }
        } else {
            result = purchaseOrderCompareMapper.updateById(compareData) > 0;
            if (result) {
                log.info("【savePurchaseOrderCompare】更新数据比对记录: è®¢å•号:{}, é¡¹æ¬¡:{}, å·®å¼‚标识:{}, å·®å¼‚数量:{}",
                        detail.getPoErpNo(), detail.getLineNo(), compareData.getDiffFlag(), compareData.getDiffQty());
            } else {
                log.error("【savePurchaseOrderCompare】更新数据比对记录失败: è®¢å•号:{}, é¡¹æ¬¡:{}",
                        detail.getPoErpNo(), detail.getLineNo());
            }
        }
    }
    /**
     * ä¿å­˜æˆ–更新采购订单明细
     *
     * @param detail é‡‡è´­è®¢å•明细数据
     */
    private void savePurchaseOrderDetail(PurchaseOrderDetail detail) {
        log.info("【savePurchaseOrderDetail】保存采购订单明细: {}, é¡¹æ¬¡: {}", detail.getPoErpNo(), detail.getLineNo());
        // ä¿å­˜é‡‡è´­è®¢å•明细
        boolean result = purchaseOrderDetailService.save(detail);
        if (result) {
            log.info("【savePurchaseOrderDetail】保存采购订单明细成功: {}, é¡¹æ¬¡: {}", detail.getPoErpNo(), detail.getLineNo());
        } else {
            log.error("【savePurchaseOrderDetail】保存采购订单明细失败: {}, é¡¹æ¬¡: {}", detail.getPoErpNo(), detail.getLineNo());
        }
    }
}
src/main/java/com/gs/xky/service/XkyService.java
@@ -44,7 +44,7 @@
        long currentTimeMillis = System.currentTimeMillis();
        long startDate = currentTimeMillis - (20 * 60 * 1000); // è®¡ç®— 20 åˆ†é’Ÿå‰çš„æ—¶é—´æˆ³
        XkyCommonParam param = XkyCommonParam.GetInit();
        XkyCommonParam<BodyParam> param = XkyCommonParam.GetInit();
        BodyParam bodyParam = new BodyParam();
        bodyParam.setStartDate(startDate);
        bodyParam.setEndDate(currentTimeMillis);
@@ -133,7 +133,7 @@
    }
    private XkyDetail getDetail(String deliveryNo) throws IOException {
        XkyCommonParam param = XkyCommonParam.GetInit();
        XkyCommonParam<BodyParam> param = XkyCommonParam.GetInit();
        // åˆ›å»º BodyParam å¯¹è±¡å¹¶èµ‹å€¼
        BodyParam bodyParam = new BodyParam();
@@ -150,7 +150,7 @@
    }
    private List<BarcodeDeliveryNo> GetBarcodeInformation(String deliveryNo) throws IOException {
        XkyCommonParam param = XkyCommonParam.GetInit();
        XkyCommonParam<BodyParam> param = XkyCommonParam.GetInit();
        // åˆ›å»º BodyParam å¯¹è±¡å¹¶èµ‹å€¼
        BodyParam bodyParam = new BodyParam();
src/main/java/com/gs/xky/task/PurchaseOrderSyncTask.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package com.gs.xky.task;
import com.gs.xky.service.PurchaseService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
 * é‡‡è´­è®¢å•同步定时任务
 */
@Component
@RequiredArgsConstructor
public class PurchaseOrderSyncTask {
    private static final Logger log = LoggerFactory.getLogger(PurchaseOrderSyncTask.class);
    private final PurchaseService purchaseService;
    /**
     * å®šæ—¶æ‰§è¡Œé‡‡è´­è®¢å•同步任务
     * æ¯å¤©12点整执行一次
     * è®¾ç½®ä¸º12点05分执行,避免与其他定时任务冲突
     */
    @Scheduled(cron = "0 5 12 * * ?")
    public void syncPurchaseOrders() {
        log.info("【syncPurchaseOrders】开始执行采购订单同步任务");
        try {
            purchaseService.syncPurchaseOrderDetails();
            log.info("【syncPurchaseOrders】采购订单同步任务执行成功");
        } catch (IOException e) {
            log.error("【syncPurchaseOrders】采购订单同步任务执行异常: {}", e.getMessage(), e);
        }
    }
}
src/main/resources/mapper/MesRohInDataMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
<?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="com.gs.xky.mapper.MesRohInDataMapper">
</mapper>
src/main/resources/mapper/MesRohInMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
<?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="com.gs.xky.mapper.MesRohInMapper">
</mapper>
src/main/resources/mapper/PurchaseOrderCompareMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
<?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="com.gs.xky.mapper.PurchaseOrderCompareMapper">
</mapper>
src/main/resources/mapper/PurchaseOrderDetailMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
<?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="com.gs.xky.mapper.PurchaseOrderDetailMapper">
</mapper>
src/test/java/com/gs/xky/XkyApplicationTests.java
@@ -1,7 +1,10 @@
package com.gs.xky;
import com.alibaba.fastjson.JSON;
import com.gs.xky.config.*;
import com.gs.xky.config.ApiResponse;
import com.gs.xky.config.BodyParam;
import com.gs.xky.config.DataAcquisitionConfiguration;
import com.gs.xky.config.XkyCommonParam;
import com.gs.xky.dto.BarcodeDeliveryNo;
import com.gs.xky.dto.XkyDetail;
import com.gs.xky.entity.MesInvItemArn;
@@ -34,6 +37,8 @@
    @Autowired
    private MesInvItemArnService invItemArnService;
    @Autowired
    private PurchaseService service;
    @Test
    void contextLoads() throws IOException {
@@ -46,7 +51,7 @@
    @Test
    public void getDeviceRealTimeData() throws IOException {
         xkyService.GetSaveDetail();
        xkyService.GetSaveDetail();
    }
    @Test
@@ -132,7 +137,6 @@
        System.out.println(jsonString);
    }
    @Test
    void cs2() throws IOException {
//        DingTalkParam dingTalkParam = new DingTalkParam(1);
@@ -154,7 +158,7 @@
    @Test
    void cs3() throws IOException {
        String str = "{\"state\":\"500\",\"msg\":\"{\\\"Result\\\":{\\\"ResponseStatus\\\":{\\\"ErrorCode\\\":500,\\\"IsSuccess\\\":false,\\\"Errors\\\":[{\\\"FieldName\\\":null,\\\"Message\\\":\\\"明细信息第1行的生产通知单值为:【127147】不存在;\\\\r\\\\n\\\",\\\"DIndex\\\":0}],\\\"SuccessEntitys\\\":[],\\\"SuccessMessages\\\":[],\\\"MsgCode\\\":11},\\\"Id\\\":\\\"\\\",\\\"Number\\\":\\\"\\\",\\\"NeedReturnData\\\":[{}]}}\"}";
        service.syncPurchaseOrderDetails();
    }
}