云
4 天以前 f02d0df2f1dfc7a8b775cf50d45375e57628a5ef
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/invoice/CrmInvoiceServiceImpl.java
@@ -439,41 +439,42 @@
    /**
     * 校验销售订单、销售出库单,并回填出库单号
     *
     * 销售订单、销售出库单均为选填:填写了才按对应规则校验,未填写直接跳过(与前端一致)。
     * 校验顺序:销售订单存在 -> 已审核 -> 客户/合同一致 -> 订单剩余可开票;
     * 再校验出库单存在 -> 已完成 -> 属于该订单 -> 客户一致 -> 出库单剩余可开票。
     */
    private void validateSaleOrderAndOut(CrmInvoiceSaveReqVO reqVO) {
        if (reqVO.getSaleOrderId() == null) {
            throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_REQUIRED);
        }
        // 1. 销售订单
        ErpSaleOrderRespDTO saleOrder = saleOrderApi.getSaleOrder(reqVO.getSaleOrderId()).getCheckedData();
        if (saleOrder == null) {
            throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_EXISTS, reqVO.getSaleOrderId());
        }
        if (ObjectUtil.notEqual(saleOrder.getStatus(), ERP_SALE_ORDER_STATUS_APPROVE)) {
            throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_APPROVE, saleOrder.getNo(),
                    erpAuditStatusName(saleOrder.getStatus()));
        }
        if (ObjectUtil.notEqual(saleOrder.getCustomerId(), reqVO.getCustomerId())
                || (saleOrder.getContractId() != null
                && ObjectUtil.notEqual(saleOrder.getContractId(), reqVO.getContractId()))) {
            throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_MISMATCH, saleOrder.getNo(),
                    saleOrder.getCustomerId(), saleOrder.getContractId(), reqVO.getCustomerId(), reqVO.getContractId());
        }
        // 1.1 订单剩余可开票金额 = 订单金额 - 该订单已占用开票金额(审批中 + 审批通过)
        BigDecimal orderTotalPrice = zeroIfNull(saleOrder.getTotalPrice());
        BigDecimal orderInvoicedPrice = sumInvoicePrice(invoiceMapper.selectListBySaleOrderIdAndStatus(
                reqVO.getSaleOrderId(), INVOICE_OCCUPY_STATUSES), reqVO.getId());
        BigDecimal orderRemainPrice = orderTotalPrice.subtract(orderInvoicedPrice);
        if (reqVO.getPrice() != null && reqVO.getPrice().compareTo(orderRemainPrice) > 0) {
            throw exception(INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_ORDER, saleOrder.getNo(),
                    formatPrice(orderRemainPrice), formatPrice(orderTotalPrice), formatPrice(orderInvoicedPrice));
        // 1. 销售订单(选填)
        ErpSaleOrderRespDTO saleOrder = null;
        if (reqVO.getSaleOrderId() != null) {
            saleOrder = saleOrderApi.getSaleOrder(reqVO.getSaleOrderId()).getCheckedData();
            if (saleOrder == null) {
                throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_EXISTS, reqVO.getSaleOrderId());
            }
            if (ObjectUtil.notEqual(saleOrder.getStatus(), ERP_SALE_ORDER_STATUS_APPROVE)) {
                throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_NOT_APPROVE, saleOrder.getNo(),
                        erpAuditStatusName(saleOrder.getStatus()));
            }
            if (ObjectUtil.notEqual(saleOrder.getCustomerId(), reqVO.getCustomerId())
                    || (saleOrder.getContractId() != null
                    && ObjectUtil.notEqual(saleOrder.getContractId(), reqVO.getContractId()))) {
                throw exception(INVOICE_CREATE_FAIL_SALE_ORDER_MISMATCH, saleOrder.getNo(),
                        saleOrder.getCustomerId(), saleOrder.getContractId(), reqVO.getCustomerId(), reqVO.getContractId());
            }
            // 1.1 订单剩余可开票金额 = 订单金额 - 该订单已占用开票金额(审批中 + 审批通过)
            BigDecimal orderTotalPrice = zeroIfNull(saleOrder.getTotalPrice());
            BigDecimal orderInvoicedPrice = sumInvoicePrice(invoiceMapper.selectListBySaleOrderIdAndStatus(
                    reqVO.getSaleOrderId(), INVOICE_OCCUPY_STATUSES), reqVO.getId());
            BigDecimal orderRemainPrice = orderTotalPrice.subtract(orderInvoicedPrice);
            if (reqVO.getPrice() != null && reqVO.getPrice().compareTo(orderRemainPrice) > 0) {
                throw exception(INVOICE_CREATE_FAIL_PRICE_EXCEEDS_SALE_ORDER, saleOrder.getNo(),
                        formatPrice(orderRemainPrice), formatPrice(orderTotalPrice), formatPrice(orderInvoicedPrice));
            }
        }
        // 2. 开票申请必须绑定已完成的销售出库单
        // 2. 销售出库单(选填)
        if (reqVO.getSaleOutId() == null) {
            throw exception(INVOICE_CREATE_FAIL_SALE_OUT_REQUIRED);
            return;
        }
        MesWmProductSalesRespDTO saleOut = productSalesApi.getProductSales(reqVO.getSaleOutId());
        if (saleOut == null) {
@@ -483,7 +484,8 @@
            throw exception(INVOICE_CREATE_FAIL_SALE_OUT_NOT_FINISHED, saleOut.getCode(),
                    productSalesStatusName(saleOut.getStatus()));
        }
        if (saleOut.getSaleOrderId() != null && ObjectUtil.notEqual(saleOut.getSaleOrderId(), reqVO.getSaleOrderId())) {
        if (saleOrder != null && saleOut.getSaleOrderId() != null
                && ObjectUtil.notEqual(saleOut.getSaleOrderId(), reqVO.getSaleOrderId())) {
            throw exception(INVOICE_CREATE_FAIL_SALE_OUT_MISMATCH_ORDER, saleOut.getCode(),
                    saleOrder.getNo(), saleOut.getSaleOrderId());
        }