昨天 684e4306a08feeae188070f264148e6765da8dcf
src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -36,6 +36,8 @@
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
@@ -47,6 +49,10 @@
@RequiredArgsConstructor
public class ShippingInfoServiceImpl extends ServiceImpl<ShippingInfoMapper, ShippingInfo> implements ShippingInfoService {
    /**
     * listPage 的行来源标记:shipping=发货单,oilOut=销售类油品出库
     */
    private static final String SOURCE_OIL_OUT = "oilOut";
    private final ShippingInfoMapper shippingInfoMapper;
@@ -68,8 +74,24 @@
        IPage<ShippingInfoDto> listPage = shippingInfoMapper.listPage(page, req);
        listPage.getRecords().forEach(item -> {
            item.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, item.getId()));
            // 油品出库行没有 shipping_product_detail,批号明细只能由出库记录自身字段构造
            if (SOURCE_OIL_OUT.equals(item.getSource())) {
                item.setBatchNoList(buildOilOutBatchNoList(item));
            }
        });
        return listPage;
    }
    /**
     * 油品出库行的批号明细,供发货台账详情弹框的「批号」明细表展示
     */
    private List<ShippingProductDetailDto> buildOilOutBatchNoList(ShippingInfoDto item) {
        ShippingProductDetailDto detail = new ShippingProductDetailDto();
        detail.setBatchNo(item.getOutBatchNo());
        detail.setProductName(item.getProductName());
        detail.setSpecificationModel(item.getSpecificationModel());
        detail.setDeliveryQuantity(item.getTotalQuantity());
        return Collections.singletonList(detail);
    }
    @Override
@@ -171,25 +193,75 @@
    @Override
    public boolean addReq(ShippingInfoDto req) {
        // 校验该产品是否已有待审核/审核中的发货记录,防止重复提交
        Long salesLedgerProductId = req.getSalesLedgerProductId();
        if (salesLedgerProductId != null) {
            long pendingCount = this.count(new LambdaQueryWrapper<ShippingInfo>()
                    .eq(ShippingInfo::getSalesLedgerProductId, salesLedgerProductId)
                    .in(ShippingInfo::getStatus, "待审核", "审核中"));
            if (pendingCount > 0) {
                throw new RuntimeException("该产品已有待审核的发货记录,请勿重复提交");
            }
        }
                LoginUser loginUser = SecurityUtils.getLoginUser();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String sh = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SH","shipping_no",req.getCreateTime());
        // 先保存发货单,再发起审批;无审核人自动通过时需要按发货编号回写发货状态。
        req.setShippingNo(sh);
        req.setStatus("待审核");
        boolean save = this.add(req);
        // 发货审批
        ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectOne(
                new LambdaQueryWrapper<ApprovalTemplate>()
                        .eq(ApprovalTemplate::getBusinessType, 7L)
                        .eq(ApprovalTemplate::getDeleted, 0)
                        .orderByDesc(ApprovalTemplate::getId)
                        .last("LIMIT 1")
        );
        if (approvalTemplate == null) {
            throw new RuntimeException("请先配置发货审批模板");
        }
        ApprovalInstanceDto approvalInstance = new ApprovalInstanceDto();
        approvalInstance.setTemplateId(approvalTemplateMapper.selectOne(new LambdaQueryWrapper<ApprovalTemplate>().eq(ApprovalTemplate::getBusinessType,6L).orderByDesc(ApprovalTemplate::getId).last("LIMIT 1")).getId());
        approvalInstance.setTemplateName(approvalTemplateMapper.selectOne(new LambdaQueryWrapper<ApprovalTemplate>().eq(ApprovalTemplate::getBusinessType,6L).orderByDesc(ApprovalTemplate::getId).last("LIMIT 1")).getTemplateName());
        approvalInstance.setTemplateId(approvalTemplate.getId());
        approvalInstance.setTemplateName(approvalTemplate.getTemplateName());
        approvalInstance.setBusinessId(req.getId());
        approvalInstance.setBusinessType(7L);
        approvalInstance.setCurrentLevel(1);
        approvalInstance.setTitle(sh+"审批");
        approvalInstance.setTitle(sh);
        approvalInstance.setApplicantId(loginUser.getUserId());
        approvalInstance.setApplicantName(loginUser.getNickName());
        approvalInstance.setApplyTime(LocalDateTime.now());
        approvalInstanceService.add(approvalInstance);
        // 创建审批实例后,更新发货状态为"审核中",使前端正确显示审批状态
        req.setStatus("审核中");
        this.updateById(req);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addShippedFromOutbound(ShippingInfoDto req) {
        // 仓储物流出库即发货:不发起发货审批,直接落为已发货,库存由 add 内部扣减
        req.setShippingNo(OrderUtils.countTodayByCreateTime(
                shippingInfoMapper, "SH", "shipping_no", LocalDateTime.now()));
        req.setStatus("已发货");
        if (req.getShippingDate() == null) {
            req.setShippingDate(new Date());
        }
        this.add(req);
        return req.getId();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelByOutbound(Long shippingInfoId) {
        if (shippingInfoId == null) {
            return;
        }
        // 回滚该发货单占用的库存
        stockUtils.deleteStockOutRecord(shippingInfoId, StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
        shippingProductDetailMapper.delete(new LambdaQueryWrapper<ShippingProductDetail>()
                .eq(ShippingProductDetail::getShippingInfoId, shippingInfoId));
        this.removeById(shippingInfoId);
    }
}