package com.vincent.rsf.server.manager.schedules; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.config.SysStockProperties; import com.vincent.rsf.server.common.utils.DateUtils; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.enums.*; import com.vincent.rsf.server.manager.service.*; import com.vincent.rsf.server.manager.service.impl.WarehouseAreasItemServiceImpl; import com.vincent.rsf.server.system.constant.GlobalConfigCode; import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.entity.Config; import com.vincent.rsf.server.system.entity.FieldsItem; import com.vincent.rsf.server.system.service.ConfigService; import com.vincent.rsf.server.system.service.FieldsItemService; import com.vincent.rsf.server.system.service.impl.FieldsItemServiceImpl; import com.vincent.rsf.server.system.utils.SerialRuleUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; /** * @author Ryan * @version 1.0 * @title ScheduleJobs * @description * @create 2025/3/3 15:38 */ @Slf4j @Component public class ScheduleJobs { @Autowired private PurchaseService purchaseService; @Autowired private PurchaseItemService purchaseItemService; @Autowired private AsnOrderService asnOrderService; @Autowired private MatnrService matnrService; @Autowired private AsnOrderItemService asnOrderItemService; @Resource private SysStockProperties flowProperties; @Autowired private ConfigService configService; @Autowired private WarehouseAreasService warehouseAreasService; @Autowired private WarehouseAreasItemServiceImpl warehouseAreasItemService; @Autowired private CompanysService companysService; @Autowired private TransferService transferService; @Autowired private OutStockService outStockService; @Autowired private FieldsItemService fieldsItemService; /** * 自动收货:仅当 DirectWaitPakin 配置为 true 时执行,将未执行入库单直接收货并写入收货区,更新单据状态为收货完成。 * 不影响云仓WMS入库接口(8.3 同步单)与组托流程;关闭时不做任何操作。 */ @Scheduled(cron = "0/25 * * * * ?") @Transactional(rollbackFor = Exception.class) public synchronized void IgnoreReceipt() { Config config = configService.getOne(new LambdaQueryWrapper().eq(Config::getFlag, GlobalConfigCode.DIRECT_WAIT_PAKIN)); if (Objects.isNull(config) || !Boolean.parseBoolean(config.getVal())) { return; } List orders = asnOrderService.list(new LambdaQueryWrapper() .eq(WkOrder::getType, OrderType.ORDER_IN.type) .eq(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val)); if (orders.isEmpty()) { return; } WarehouseAreas receiptArea = warehouseAreasService.getOne(new LambdaQueryWrapper() .eq(WarehouseAreas::getType, WarehouseAreasType.WAREHOUSE_AREAS_TYPE_RECEIPT.type), false); for (WkOrder order : orders) { if (OrderWorkType.ORDER_WORK_TYPE_OTHER_TERANSFER.type.equals(order.getWkType())) { WkOrder one = outStockService.getOne(new LambdaQueryWrapper() .eq(WkOrder::getPoId, order.getPoId()) .eq(WkOrder::getWkType, OrderWorkType.ORDER_WORK_TYPE_STOCK_TERANSFER.type)); if (Objects.isNull(one)) { throw new CoolException("数据错误"); } if (!one.getExceStatus().equals(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val)) { continue; } } List orderItems = asnOrderItemService.list(new LambdaQueryWrapper().eq(WkOrderItem::getOrderId, order.getId())); if (orderItems.isEmpty()) { continue; } for (WkOrderItem item : orderItems) { if (receiptArea != null) { Matnr matnr = matnrService.getOne(new LambdaQueryWrapper().eq(Matnr::getId, item.getMatnrId())); if (Objects.isNull(matnr)) { throw new CoolException("物料不存在!!"); } try { updateReceipt(receiptArea, item, order, matnr); } catch (Exception e) { throw new CoolException(e.getMessage()); } } if (!asnOrderItemService.update(new LambdaUpdateWrapper().set(WkOrderItem::getQty, item.getAnfme()).eq(WkOrderItem::getId, item.getId()))) { throw new CoolException("收货单明细完成数量修改失败!!"); } } if (!asnOrderService.update(new LambdaUpdateWrapper() .set(WkOrder::getQty, order.getAnfme()) .set(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_RECEIPT_DONE.val) .eq(WkOrder::getId, order.getId()))) { throw new CoolException("收货单状态修改失败!!"); } } } /** * 收货区库存更新(仅 DirectWaitPakin 启用时由 IgnoreReceipt 调用) */ @Transactional(rollbackFor = Exception.class) public void updateReceipt(WarehouseAreas areasItem, WkOrderItem orderItem, WkOrder wkOrder, Matnr matnr) throws Exception { Companys companys = new Companys(); if (StringUtils.isNoneBlank(orderItem.getSplrCode())) { companys = companysService.getOne(new LambdaQueryWrapper().eq(Companys::getCode, orderItem.getSplrCode())); } if (Objects.isNull(companys)) { companys = new Companys(); } WarehouseAreasItem item = new WarehouseAreasItem(); item.setTrackCode(orderItem.getBarcode()) .setAreaName(areasItem.getName()) .setAreaId(areasItem.getId()) .setAsnItemId(orderItem.getId()) .setAsnCode(wkOrder.getCode()) .setAsnId(wkOrder.getId()) .setProdTime(orderItem.getProdTime()) .setPlatItemId(orderItem.getPlatItemId()) .setPlatOrderCode(orderItem.getPlatOrderCode()) .setPlatWorkCode(orderItem.getPlatWorkCode()) .setProjectCode(orderItem.getProjectCode()) .setSplrId(companys.getId()) .setUnit(orderItem.getStockUnit()) .setStockUnit(orderItem.getStockUnit()) .setMatnrCode(matnr.getCode()) .setAnfme(orderItem.getAnfme()) .setMatnrId(matnr.getId()) .setIsptResult(orderItem.getIsptResult()) .setMaktx(matnr.getName()) .setSplrBatch(orderItem.getSplrBatch()) .setWeight(matnr.getWeight()) .setFieldsIndex(orderItem.getFieldsIndex()) .setShipperId(matnr.getShipperId()); if (StringUtils.isNotBlank(orderItem.getFieldsIndex())) { List warehousList = warehouseAreasItemService.list(new LambdaQueryWrapper().eq(WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex())); WarehouseAreasItem warehousItem = warehousList.isEmpty() ? null : warehousList.get(0); if (Objects.nonNull(warehousItem)) { List fieldsList = fieldsItemService.list(new LambdaQueryWrapper().eq(FieldsItem::getUuid, orderItem.getFieldsIndex()).last("LIMIT 1")); FieldsItem fieldsItem = fieldsList.isEmpty() ? null : fieldsList.get(0); if (Objects.nonNull(fieldsItem)) { // 票号已在收货区时跳过推送,避免定时任务反复抛错;视为已收货,由后续逻辑更新单据状态 log.warn("票号:{} 已在收货区,跳过推送", fieldsItem.getValue()); return; } } } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() .eq(WarehouseAreasItem::getMatnrCode, orderItem.getMatnrCode()) .eq(!Cools.isEmpty(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex()) .eq(WarehouseAreasItem::getAsnCode, orderItem.getOrderCode()) .eq(StringUtils.isNotBlank(orderItem.getSplrBatch()), WarehouseAreasItem::getSplrBatch, orderItem.getSplrBatch()); if (Objects.isNull(orderItem.getIsptResult())) { queryWrapper.isNull(WarehouseAreasItem::getIsptResult); } else { queryWrapper.eq(WarehouseAreasItem::getIsptResult, orderItem.getIsptResult()); } WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(queryWrapper); if (Objects.nonNull(serviceOne)) { item.setId(serviceOne.getId()); Double anfme = Math.round((item.getAnfme() + serviceOne.getAnfme()) * 10000) / 10000.0; item.setAnfme(anfme); } if (!warehouseAreasItemService.saveOrUpdate(item)) { throw new CoolException("收货失败!!"); } } /** * @return * @throws * @author Ryan * @description 根据PO单据生成ASN单, 自动生成ASN单为全量生成 * @time 2025/3/3 15:44 */ @Scheduled(cron = "0 0/05 * * * ? ") @Transactional(rollbackFor = Exception.class) public synchronized void genAsnOrder() { //判断是否开启自动生成ASN单据 if (!flowProperties.getFlagAutoAsn()) { return; } //获取未生成ASN单据 List purchases = purchaseService.list(new LambdaQueryWrapper().eq(Purchase::getExceStatus, 0)); //PO单为空,直接跳出当前任务 if (purchases.isEmpty()) { return; } //生成ASN单据 purchases.forEach(purchase -> { if (!Objects.isNull(purchase.getStartTime())) { //判断起始时间是否大于当前时间 if (DateUtils.compareDate(new Date(), purchase.getStartTime())) { return; } } List items = purchaseItemService.list(new LambdaQueryWrapper().eq(PurchaseItem::getPurchaseId, purchase.getId())); if (items.isEmpty()) { throw new CoolException("子列表数据为空,请查询PO单是否正确录入!!"); } WkOrder order = new WkOrder(); //根据编码规则生成ASN单号 String code = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_ASN_ORDER, purchase); order.setAnfme(purchase.getAnfme()) .setCode(code) .setArrTime(purchase.getPreArr()) .setQty(purchase.getQty()) .setPoId(purchase.getId()) .setPoCode(purchase.getCode()); if (!asnOrderService.save(order)) { throw new CoolException("ASN单据保存失败!!"); } List orderItems = new ArrayList<>(); items.forEach(item -> { WkOrderItem orderItem = new WkOrderItem(); Matnr matnr = matnrService.getOne(new LambdaQueryWrapper().eq(Matnr::getCode, item.getMatnrCode())); if (Objects.isNull(matnr)) { throw new CoolException("数据错误:当前物料不存在!!"); } String trackCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_LABEL_CODE, item); if (StringUtils.isBlank(trackCode)) { throw new CoolException("单据跟踪码生成失败:请检查「sys_asn_mantr_label」是否配置完成!!"); } // String barcode = code + matnr.getCode(); orderItem.setAnfme(item.getAnfme()) .setOrderId(order.getId()) .setQty(item.getQty()) .setSplrName(item.getSplrName()) .setOrderCode(code) .setSplrCode(item.getSplrCode()) .setPoDetlId(item.getId()) .setPlatItemId(item.getPlatItemId()) .setTrackCode(trackCode) .setPoCode(purchase.getCode()) .setPurQty(item.getAnfme()) .setPurUnit(item.getUnit()) .setMatnrCode(matnr.getCode()) .setMaktx(matnr.getName()) .setMatnrId(matnr.getId()); orderItems.add(orderItem); }); if (!asnOrderItemService.saveBatch(orderItems)) { throw new CoolException(("Asn单据明细保存失败!!")); } //任务执行完成,修改已完成数量和PO单执行状态 purchase.setQty(purchase.getAnfme()) .setExceStatus(POExceStatus.PO_EXCE_STATUS_EXCE_ING.val); if (!purchaseService.saveOrUpdate(purchase)) { throw new CoolException("PO单执行完成后,保存失败!!"); } }); } /** * @param * @return * @author Ryan * @description 生成物料标签 * @time 2025/3/29 12:35 */ @Scheduled(cron = "0 0/05 * * * ? ") @Transactional(rollbackFor = Exception.class) public void generateMatnrLabel() { List list = asnOrderItemService.list(new LambdaQueryWrapper() .isNull(WkOrderItem::getTrackCode) .select(WkOrderItem::getId)); if (Objects.isNull(list) || list.isEmpty()) { return; } List items = new ArrayList<>(); list.forEach(item -> { String trackCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_LABEL_CODE, item); if (StringUtils.isBlank(trackCode)) { throw new CoolException("单据跟踪码生成失败:请检查「sys_asn_mantr_label」是否配置完成!!"); } // item.setTrackCode(trackCode); item.setBarcode(trackCode); items.add(item); }); if (!asnOrderItemService.updateBatchById(items)) { throw new CoolException("生成编码失败!!"); } } }