| | |
| | | package cn.iocoder.yudao.module.erp.service.purchase; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementRespVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.statement.ErpSupplierStatementSummaryRespVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInvoiceDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; |
| | |
| | | return respVO; |
| | | } |
| | | |
| | | @Override |
| | | public List<ErpSupplierStatementSummaryRespVO> getSupplierSummaryList(ErpSupplierStatementSummaryReqVO reqVO) { |
| | | // 1. 口径与单个供应商详情保持一致:订单按审核状态过滤、来票不过滤状态、付款含未审核/审批中/已审核 |
| | | List<Integer> orderStatuses = Boolean.TRUE.equals(reqVO.getIncludeUnapprovedOrder()) |
| | | ? List.of(ErpAuditStatus.PROCESS.getStatus(), ErpAuditStatus.APPROVING.getStatus(), |
| | | ErpAuditStatus.APPROVE.getStatus()) |
| | | : List.of(ErpAuditStatus.APPROVE.getStatus()); |
| | | List<ErpPurchaseOrderDO> orders = purchaseOrderMapper.selectListByOrderTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime(), orderStatuses); |
| | | List<ErpPurchaseInvoiceDO> invoices = purchaseInvoiceMapper.selectListByInvoiceTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime()); |
| | | List<Integer> paymentStatuses = List.of(ErpAuditStatus.PROCESS.getStatus(), |
| | | ErpAuditStatus.APPROVING.getStatus(), ErpAuditStatus.APPROVE.getStatus()); |
| | | List<ErpFinancePaymentDO> payments = financePaymentMapper.selectListByPaymentTimeBetween( |
| | | reqVO.getBeginTime(), reqVO.getEndTime(), paymentStatuses); |
| | | |
| | | // 2. 按供应商汇总 |
| | | Map<Long, ErpSupplierStatementSummaryRespVO> summaryMap = new HashMap<>(); |
| | | for (ErpPurchaseOrderDO order : orders) { |
| | | if (order.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, order.getSupplierId()); |
| | | summary.setOrderCount(summary.getOrderCount() + 1); |
| | | summary.setTotalPurchaseAmount(summary.getTotalPurchaseAmount().add(zero(order.getTotalPrice()))); |
| | | } |
| | | for (ErpPurchaseInvoiceDO invoice : invoices) { |
| | | if (invoice.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, invoice.getSupplierId()); |
| | | summary.setInvoiceCount(summary.getInvoiceCount() + 1); |
| | | summary.setTotalInvoiceAmount(summary.getTotalInvoiceAmount().add(zero(invoice.getPrice()))); |
| | | } |
| | | for (ErpFinancePaymentDO payment : payments) { |
| | | if (payment.getSupplierId() == null) { |
| | | continue; |
| | | } |
| | | ErpSupplierStatementSummaryRespVO summary = getOrCreateSummary(summaryMap, payment.getSupplierId()); |
| | | summary.setPaymentCount(summary.getPaymentCount() + 1); |
| | | summary.setTotalPaymentAmount(summary.getTotalPaymentAmount().add(zero(payment.getPaymentPrice()))); |
| | | } |
| | | |
| | | // 3. 填充供应商编码 / 名称(SRM 中已删除的供应商用 ID 兜底展示,避免出现空行) |
| | | Map<Long, SrmSupplierRespDTO> supplierMap = new HashMap<>(); |
| | | if (!summaryMap.isEmpty()) { |
| | | List<SrmSupplierRespDTO> suppliers = srmSupplierApi.getSupplierList(summaryMap.keySet()).getCheckedData(); |
| | | if (CollUtil.isNotEmpty(suppliers)) { |
| | | suppliers.forEach(item -> supplierMap.put(item.getId(), item)); |
| | | } |
| | | } |
| | | for (ErpSupplierStatementSummaryRespVO summary : summaryMap.values()) { |
| | | summary.setUnpaidAmount(summary.getTotalInvoiceAmount().subtract(summary.getTotalPaymentAmount())); |
| | | SrmSupplierRespDTO supplier = supplierMap.get(summary.getSupplierId()); |
| | | if (supplier == null) { |
| | | summary.setSupplierName("未知供应商(ID=" + summary.getSupplierId() + ")"); |
| | | continue; |
| | | } |
| | | summary.setSupplierCode(supplier.getCode()); |
| | | summary.setSupplierName(StrUtil.blankToDefault(supplier.getName(), |
| | | "未命名供应商(ID=" + summary.getSupplierId() + ")")); |
| | | } |
| | | |
| | | // 4. 未付余额多的排前面,其次按采购额、供应商名称 |
| | | Comparator<ErpSupplierStatementSummaryRespVO> comparator = |
| | | Comparator.comparing(ErpSupplierStatementSummaryRespVO::getUnpaidAmount, |
| | | Comparator.nullsFirst(Comparator.<BigDecimal>naturalOrder())) |
| | | .thenComparing(ErpSupplierStatementSummaryRespVO::getTotalPurchaseAmount, |
| | | Comparator.nullsFirst(Comparator.<BigDecimal>naturalOrder())) |
| | | .reversed() |
| | | .thenComparing(ErpSupplierStatementSummaryRespVO::getSupplierName, |
| | | Comparator.nullsLast(Comparator.naturalOrder())); |
| | | return summaryMap.values().stream() |
| | | .sorted(comparator) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private ErpSupplierStatementSummaryRespVO getOrCreateSummary( |
| | | Map<Long, ErpSupplierStatementSummaryRespVO> summaryMap, Long supplierId) { |
| | | return summaryMap.computeIfAbsent(supplierId, id -> { |
| | | ErpSupplierStatementSummaryRespVO summary = new ErpSupplierStatementSummaryRespVO(); |
| | | summary.setSupplierId(id); |
| | | summary.setOrderCount(0); |
| | | summary.setInvoiceCount(0); |
| | | summary.setPaymentCount(0); |
| | | summary.setTotalPurchaseAmount(BigDecimal.ZERO); |
| | | summary.setTotalInvoiceAmount(BigDecimal.ZERO); |
| | | summary.setTotalPaymentAmount(BigDecimal.ZERO); |
| | | summary.setUnpaidAmount(BigDecimal.ZERO); |
| | | return summary; |
| | | }); |
| | | } |
| | | |
| | | private BigDecimal zero(BigDecimal value) { |
| | | return value != null ? value : BigDecimal.ZERO; |
| | | } |