liu
昨天 429866e3d0a2eee95916407b2e1dfa7de6f407ea
feat(erp): 采购来票登记过滤已开完票订单

- ErpPurchaseOrderPageReqVO 新增 remainPriceEnable 参数:仅返回剩余可开票金额>0 的订单
- 分页查询按 totalPrice > 已来票金额合计 过滤已开完票订单(关联 erp_purchase_invoice 动态计算)
- ErpPurchaseOrderRespVO 新增 remainInvoicePrice 字段(订单总金额 - 已来票金额)
- 新增按订单批量统计来票金额的服务方法

Co-Authored-By: Claude <noreply@anthropic.com>
已修改7个文件
53 ■■■■■ 文件已修改
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderPageReqVO.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInvoiceMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInvoiceService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInvoiceServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
@@ -17,6 +17,7 @@
import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderSourceTypeEnum;
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInvoiceService;
import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderService;
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
@@ -56,6 +57,8 @@
    @Resource
    private ErpPurchaseOrderService purchaseOrderService;
    @Resource
    private ErpPurchaseInvoiceService purchaseInvoiceService;
    @Resource
    private SrmSupplierApi srmSupplierApi;
@@ -211,6 +214,9 @@
        // 1.5 单位信息
        Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap(
                convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductUnitId));
        // 1.6 已来票金额:按采购订单统计,用于计算剩余可开票金额
        Map<Long, BigDecimal> invoicePriceSumMap = purchaseInvoiceService
                .getPurchaseInvoicePriceSumMapByOrderIds(convertSet(pageResult.getList(), ErpPurchaseOrderDO::getId));
        // 2. 开始拼接
        return BeanUtils.toBean(pageResult, ErpPurchaseOrderRespVO.class, purchaseOrder -> {
            purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class,
@@ -225,6 +231,9 @@
            MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname()));
            purchaseOrder.setSourceTypeName(ErpPurchaseOrderSourceTypeEnum.WORK_ORDER.getType()
                    .equals(purchaseOrder.getSourceType()) ? "生产工单" : null);
            // 剩余可开票金额 = 订单总金额 - 已来票金额
            purchaseOrder.setRemainInvoicePrice(purchaseOrder.getTotalPrice().subtract(
                    invoicePriceSumMap.getOrDefault(purchaseOrder.getId(), BigDecimal.ZERO)));
        });
    }
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderPageReqVO.java
@@ -77,4 +77,13 @@
    @Schema(description = "是否可退货", example = "true")
    private Boolean returnEnable;
    /**
     * 仅返回剩余可开票金额大于 0 的订单
     *
     * 用于"采购来票"登记时选择采购订单:金额已开完(剩余可开票金额 &lt;= 0)的订单不展示。
     * 剩余可开票金额 = totalPrice - SUM(erp_purchase_invoice.price)
     */
    @Schema(description = "是否仅返回剩余可开票金额大于 0 的订单(采购来票登记使用)", example = "true")
    private Boolean remainPriceEnable;
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java
@@ -59,6 +59,9 @@
    @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
    private BigDecimal totalTaxPrice;
    @Schema(description = "剩余可开票金额(订单总金额 - 已来票金额),单位:元", example = "100.00")
    private BigDecimal remainInvoicePrice;
    @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88")
    private BigDecimal discountPercent;
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInvoiceMapper.java
@@ -7,6 +7,7 @@
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
/**
@@ -39,4 +40,9 @@
                .eq(ErpPurchaseInvoiceDO::getSupplierId, supplierId));
    }
    default List<ErpPurchaseInvoiceDO> selectListByOrderIds(Collection<Long> orderIds) {
        return selectList(new LambdaQueryWrapperX<ErpPurchaseInvoiceDO>()
                .in(ErpPurchaseInvoiceDO::getPurchaseOrderId, orderIds));
    }
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java
@@ -57,6 +57,11 @@
            query.eq(ErpPurchaseOrderDO::getStatus, ErpAuditStatus.APPROVE.getStatus())
                    .apply("t.return_count < t.in_count");
        }
        // 可来票登记(剩余可开票金额 > 0):金额已开完的订单不展示
        if (Boolean.TRUE.equals(reqVO.getRemainPriceEnable())) {
            query.apply("t.total_price > (SELECT IFNULL(SUM(i.price), 0) FROM erp_purchase_invoice i "
                    + "WHERE i.purchase_order_id = t.id AND i.deleted = 0)");
        }
        if (reqVO.getProductId() != null) {
            query.leftJoin(ErpPurchaseOrderItemDO.class, ErpPurchaseOrderItemDO::getOrderId, ErpPurchaseOrderDO::getId)
                    .eq(reqVO.getProductId() != null, ErpPurchaseOrderItemDO::getProductId, reqVO.getProductId())
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInvoiceService.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO;
import jakarta.validation.Valid;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -91,4 +92,12 @@
     */
    List<ErpPurchaseInvoiceDO> getPurchaseInvoiceListBySupplierId(Long supplierId);
    /**
     * 根据采购订单编号列表,统计每个订单的来票金额合计(用于计算剩余可开票金额)
     *
     * @param orderIds 采购订单编号列表
     * @return Map<采购订单编号, 来票金额合计>
     */
    Map<Long, BigDecimal> getPurchaseInvoicePriceSumMapByOrderIds(Collection<Long> orderIds);
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInvoiceServiceImpl.java
@@ -20,8 +20,10 @@
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
@@ -176,4 +178,14 @@
        return invoiceMapper.selectListBySupplierId(supplierId);
    }
    @Override
    public Map<Long, BigDecimal> getPurchaseInvoicePriceSumMapByOrderIds(Collection<Long> orderIds) {
        if (CollUtil.isEmpty(orderIds)) {
            return Collections.emptyMap();
        }
        List<ErpPurchaseInvoiceDO> invoices = invoiceMapper.selectListByOrderIds(orderIds);
        return invoices.stream().collect(Collectors.groupingBy(ErpPurchaseInvoiceDO::getPurchaseOrderId,
                Collectors.mapping(ErpPurchaseInvoiceDO::getPrice, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
    }
}