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 com.gs.xky.mapper.PurchaseOrderDetailMapper;
|
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;
|
private final PurchaseOrderDetailMapper purchaseOrderDetailMapper;
|
|
/**
|
* 同步采购订单明细数据
|
* 从第三方接口获取采购订单明细数据并保存到本地数据库
|
* 注意:该接口有以下限制:
|
* 1. 访问频率不能低于2小时
|
* 2. 一次请求中时间范围不能大于24小时
|
*
|
* @throws IOException 接口调用异常
|
*/
|
public void syncPurchaseOrderDetails() throws IOException {
|
long currentTimeMillis = System.currentTimeMillis();
|
// 限制请求时间范围为24小时
|
long startDate = currentTimeMillis - (24 * 60 * 60 * 1000L);
|
|
// 先删除已有数据,避免重复
|
purchaseOrderDetailMapper.deleteByPrimaryKey();
|
purchaseOrderCompareMapper.deleteByPrimaryKey();
|
|
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());
|
|
// 分批处理数据,减少内存占用
|
int batchSize = 100; // 每批处理100条数据
|
int totalSize = orderDetails.size();
|
int batchCount = (totalSize + batchSize - 1) / batchSize; // 向上取整计算批次数
|
|
for (int i = 0; i < batchCount; i++) {
|
int fromIndex = i * batchSize;
|
int toIndex = Math.min((i + 1) * batchSize, totalSize);
|
|
log.info("【syncPurchaseOrderDetails】处理第{}批数据,范围:{}-{}", i + 1, fromIndex, toIndex);
|
|
// 获取当前批次的数据
|
List<PurchaseOrderDetail> batchDetails = orderDetails.subList(fromIndex, toIndex);
|
|
// 处理当前批次的数据
|
processBatch(batchDetails);
|
|
// 手动触发GC,释放内存(谨慎使用,仅在内存紧张时考虑)
|
// System.gc();
|
}
|
}
|
|
/**
|
* 批量处理采购订单明细数据
|
*
|
* @param batchDetails 当前批次的采购订单明细数据
|
*/
|
private void processBatch(List<PurchaseOrderDetail> batchDetails) {
|
batchDetails.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);
|
|
// 帮助GC回收不再使用的对象
|
wrapper = null;
|
erpData = null;
|
} 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.getPoWaitDeliveryQty() + detail.getReturnWaitDeliveryQty();
|
//poWaitDeliveryQty + returnWaitDeliveryQty
|
Integer srmWaitReceiveQty = srmPurchaseQty - srmReceivedQty;
|
|
// 设置SRM数据
|
compareData.setSrmPurchaseQty(srmPurchaseQty);
|
compareData.setSrmReceivedQty(srmWaitReceiveQty);
|
compareData.setSrmWaitReceiveQty(srmReceivedQty);
|
|
// 设置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());
|
}
|
}
|
}
|