package com.ruoyi.sales.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.other.service.impl.TempFileServiceImpl; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.sales.dto.SalesLedgerProductDto; import com.ruoyi.sales.dto.ShippingInfoDto; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.ShippingInfoMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.ShippingInfo; import com.ruoyi.sales.service.ShippingInfoService; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.Collections; import java.util.List; /** * @author :yys * @date : 2025/10/22 9:33 */ @Service @Slf4j public class ShippingInfoServiceImpl extends ServiceImpl implements ShippingInfoService { @Autowired private ShippingInfoMapper shippingInfoMapper; @Autowired private TempFileServiceImpl tempFileService; @Autowired private SalesLedgerProductMapper salesLedgerProductMapper; @Autowired private StockUtils stockUtils; @Autowired private CommonFileServiceImpl commonFileService; @Autowired private ApproveProcessServiceImpl approveProcessService; @Autowired private SalesLedgerMapper salesLedgerMapper; @Autowired private StockInventoryMapper stockInventoryMapper; @Override public IPage listPage(Page page, ShippingInfo req) { IPage listPage = shippingInfoMapper.listPage(page, req); listPage.getRecords().forEach(item ->{ item.setCommonFileList(commonFileService.getFileListByBusinessId(item.getId(), FileNameType.SHIP.getValue())); }); return listPage; } @Override @Transactional(rollbackFor = Exception.class) public boolean deductStock(ShippingInfoDto req) throws IOException { ShippingInfo byId = this.getById(req.getId()); if (byId == null) { throw new RuntimeException("发货信息不存在"); } return deductStockByOrder(byId.getSalesLedgerId(), req); } @Override @Transactional(rollbackFor = Exception.class) public boolean deductStockByOrder(Long salesLedgerId, ShippingInfoDto req) throws IOException { if (salesLedgerId == null) { throw new RuntimeException("关联订单不可为空"); } SalesLedger salesLedger = salesLedgerMapper.selectById(salesLedgerId); if (salesLedger == null) { throw new RuntimeException("关联订单不存在"); } // 检查该订单下是否还有未发货的记录 List unsentShippings = this.list(new LambdaQueryWrapper() .eq(ShippingInfo::getSalesLedgerId, salesLedgerId) .ne(ShippingInfo::getStatus, "已发货")); // 仅在存在未发货记录时执行库存扣减 if (CollectionUtils.isNotEmpty(unsentShippings)) { // 获取该订单下所有的产品信息进行汇总扣减 List products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper() .eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); if (CollectionUtils.isEmpty(products)) { throw new RuntimeException("该订单下无产品信息,无法扣减库存"); } // 汇总需求并校验库存 Map modelQtyMap = new HashMap<>(); for (SalesLedgerProduct p : products) { if (p.getProductModelId() == null) continue; modelQtyMap.put(p.getProductModelId(), modelQtyMap.getOrDefault(p.getProductModelId(), BigDecimal.ZERO).add(p.getQuantity())); } for (Map.Entry entry : modelQtyMap.entrySet()) { Long modelId = entry.getKey(); BigDecimal totalNeeded = entry.getValue(); StockInventory stock = stockInventoryMapper.selectOne(new LambdaQueryWrapper() .eq(StockInventory::getProductModelId, modelId)); if (stock == null) { throw new RuntimeException("产品规格ID:" + modelId + " 库存记录不存在"); } BigDecimal locked = stock.getLockedQuantity() == null ? BigDecimal.ZERO : stock.getLockedQuantity(); BigDecimal available = stock.getQualitity().subtract(locked); if (totalNeeded.compareTo(available) > 0) { throw new RuntimeException("产品规格ID:" + modelId + " 总计需求 " + totalNeeded + ",可用库存 " + available + ",库存充足校验未通过"); } } // 执行订单下所有产品的库存扣减 for (SalesLedgerProduct p : products) { if (p.getProductModelId() == null) continue; // 使用 businessId = salesLedgerId 或当前 req.getId() stockUtils.substractStock(p.getProductModelId(), p.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), salesLedgerId); } } // 更新该订单下所有的发货记录状态为已发货 LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.set(ShippingInfo::getStatus, "已发货") .eq(ShippingInfo::getSalesLedgerId, salesLedgerId); if (req != null) { if (req.getExpressNumber() != null) updateWrapper.set(ShippingInfo::getExpressNumber, req.getExpressNumber()); if (req.getExpressCompany() != null) updateWrapper.set(ShippingInfo::getExpressCompany, req.getExpressCompany()); if (req.getShippingCarNumber() != null) updateWrapper.set(ShippingInfo::getShippingCarNumber, req.getShippingCarNumber()); if (req.getShippingDate() != null) updateWrapper.set(ShippingInfo::getShippingDate, req.getShippingDate()); } this.update(updateWrapper); // 更新订单状态为 4-已发货 if (!Integer.valueOf(4).equals(salesLedger.getDeliveryStatus())) { salesLedger.setDeliveryStatus(4); salesLedgerMapper.updateById(salesLedger); } // 迁移当前记录涉及的文件 if (req != null && req.getId() != null && CollectionUtils.isNotEmpty(req.getTempFileIds())) { tempFileService.migrateTempFilesToFormal(req.getId(), req.getTempFileIds(), FileNameType.SHIP.getValue()); } return true; } @Override public boolean delete(List ids) { List shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper() .in(ShippingInfo::getId, ids)); if(CollectionUtils.isEmpty(shippingInfos)) return false; // 删除附件 commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue()); // 扣已发货库存 for (ShippingInfo shippingInfo : shippingInfos) { if("已发货".equals(shippingInfo.getStatus())) { stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode()); } } // 删除发货审批 if(CollectionUtils.isNotEmpty(shippingInfos)){ for (ShippingInfo shippingInfo : shippingInfos){ ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper() .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo())); if(one != null){ approveProcessService.delByIds(Collections.singletonList(one.getId())); } } } return this.removeBatchByIds(ids); } @Override public List getReturnManagementDtoById(Long shippingId) { return shippingInfoMapper.getReturnManagementDtoById(shippingId ); } @Override public List getShippingInfoByCustomerName(String customerName) { return shippingInfoMapper.getShippingInfoByCustomerName(customerName); } }