src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -14,6 +14,7 @@ import com.ruoyi.framework.web.domain.R; import com.ruoyi.framework.web.page.TableDataInfo; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.dto.SalesLedgerEditFlagDto; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.service.ICommonFileService; import com.ruoyi.sales.service.ISalesLedgerService; @@ -246,23 +247,20 @@ // 获取当前页所有台账记录的 ID 集合 List<Long> salesLedgerIds = iPage.getRecords().stream().map(SalesLedger::getId).collect(Collectors.toList()); // 转换回款数据, key 为台账ID, value 为该台账的总回款金额 Map<Long, BigDecimal> receiptTotals = new HashMap<>(); // 批量查询每个台账的编辑限制标记:是否含需要生产的产品、生产计划是否已下发、是否已发货 Map<Long, SalesLedgerEditFlagDto> editFlags = salesLedgerService.getEditFlags(salesLedgerIds); for (SalesLedgerVo salesLedgerVo : iPage.getRecords()) { Long ledgerId = salesLedgerVo.getId(); // 合同总金额 BigDecimal contractAmount = salesLedgerVo.getContractAmount() == null ? BigDecimal.ZERO : salesLedgerVo.getContractAmount(); // 开票总额和回款总额 BigDecimal receiptPaymentAmountTotal = receiptTotals.getOrDefault(ledgerId, BigDecimal.ZERO); SalesLedgerEditFlagDto editFlag = editFlags.get(ledgerId); boolean needsProduction = isFlagTrue(editFlag == null ? null : editFlag.getNeedsProduction()); boolean planIssued = isFlagTrue(editFlag == null ? null : editFlag.getPlanIssued()); boolean shipped = isFlagTrue(editFlag == null ? null : editFlag.getShipped()); // 如果已经有过开票或回款操作,则不允许编辑 boolean hasReceiptOperation = receiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) > 0; salesLedgerVo.setIsEdit(hasReceiptOperation); // 需要生产的订单:生产计划已下发(含部分下发)则不允许编辑 // 走库存的订单:已发货则不允许编辑,否则可以编辑 salesLedgerVo.setIsEdit(needsProduction ? !planIssued : !shipped); salesLedgerVo.setHasProductionRecord(planIssued); salesLedgerVo.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, ledgerId)); } @@ -291,4 +289,8 @@ } return AjaxResult.success(data); } private boolean isFlagTrue(Integer flag) { return flag != null && flag == 1; } } src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -8,6 +8,7 @@ import com.ruoyi.home.dto.IncomeExpenseAnalysisDto; import com.ruoyi.purchase.vo.PurchaseReportVo; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.dto.SalesLedgerEditFlagDto; import com.ruoyi.sales.dto.SalesTrendDto; import com.ruoyi.sales.dto.StatisticsTableDto; import com.ruoyi.sales.pojo.SalesLedger; @@ -91,4 +92,12 @@ IPage<PurchaseReportVo> selectPurchaseReportVoPage(Page page, @Param("customerName") String customerName); /** * 批量查询销售台账的编辑限制标记 * * @param ids 销售台账id集合 * @return 每个台账的需要生产/生产计划已下发/已发货标记 */ List<SalesLedgerEditFlagDto> selectEditFlags(@Param("ids") List<Long> ids); } src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -9,6 +9,7 @@ import com.ruoyi.sales.dto.LossProductModelDto; import com.ruoyi.sales.dto.MonthlyAmountDto; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.dto.SalesLedgerEditFlagDto; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.vo.SalesLedgerVo; @@ -58,4 +59,12 @@ IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page); Map<String, Object> getPrintData(Long id); /** * 批量查询销售台账的编辑限制标记,key为销售台账id * * @param ids 销售台账id集合 * @return 编辑限制标记 */ Map<Long, SalesLedgerEditFlagDto> getEditFlags(List<Long> ids); } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.AmountUtils; import com.ruoyi.framework.web.domain.R; import com.ruoyi.procurementrecord.utils.StockUtils; @@ -38,6 +39,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -177,12 +179,9 @@ result = salesLedgerProductMapper.insert(salesLedgerProduct); addProductionData(salesLedgerProduct); } else { //查询原本的产品型号id result = salesLedgerProductMapper.updateById(salesLedgerProduct); /*删除对应的生产数据并重新新增*/ deleteProductionData(Arrays.asList(salesLedgerProduct.getId())); addProductionData(salesLedgerProduct); /*同步对应的生产数据:计划未下发时原地更新需求数量,保留生产计划号*/ syncProductionData(salesLedgerProduct); } // 如果插入或更新成功,并且有 salesLedgerId,才继续更新主表金额 @@ -238,6 +237,38 @@ } /** * 同步生产数据 * 需要生产:生产计划已下发时禁止修改;未下发时原地更新需求数量,保留生产计划号; * 改为走库存:删除未下发的生产计划。 */ public void syncProductionData(SalesLedgerProduct salesLedgerProduct) { if (salesLedgerProduct.getId() == null) { return; } List<ProductionPlan> productionPlans = listProductionData(salesLedgerProduct.getId()); if (CollectionUtils.isEmpty(productionPlans)) { //原来不需要生产,现在改为需要生产,补建生产计划 if (Boolean.TRUE.equals(salesLedgerProduct.getIsProduction())) { addProductionData(salesLedgerProduct); } return; } //改为走库存,删除未下发的生产计划 if (!Boolean.TRUE.equals(salesLedgerProduct.getIsProduction())) { deleteProductionData(Collections.singletonList(salesLedgerProduct.getId())); return; } if (productionPlans.stream().anyMatch(plan -> plan.getStatus() != null && plan.getStatus() != 0)) { throw new ServiceException("生产计划已下发,不能修改该销售产品"); } for (ProductionPlan productionPlan : productionPlans) { productionPlan.setQtyRequired(salesLedgerProduct.getQuantity()); productionPlan.setProductModelId(salesLedgerProduct.getProductModelId()); productionPlanMapper.updateById(productionPlan); } } /** * 删除生产计划 */ public void deleteProductionData(List<Long> productIds) { @@ -246,12 +277,12 @@ } List<ProductionPlan> productionPlans = productionPlanMapper.selectList( new LambdaQueryWrapper<ProductionPlan>() .in(ProductionPlan::getSalesLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList()))); .in(ProductionPlan::getSalesLedgerProductId, productIds)); if (CollectionUtils.isEmpty(productionPlans)) { return; } //如果生产计划已下发则不能删除 if (productionPlans.stream().anyMatch(productionPlan -> productionPlan.getStatus() != 0)) { if (productionPlans.stream().anyMatch(productionPlan -> productionPlan.getStatus() != null && productionPlan.getStatus() != 0)) { throw new RuntimeException("生产计划已下发,不能删除该销售产品"); } List<Long> ids = productionPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList()); @@ -259,6 +290,14 @@ } /** * 查询销售产品对应的生产计划 */ private List<ProductionPlan> listProductionData(Long productId) { return productionPlanMapper.selectList(new LambdaQueryWrapper<ProductionPlan>() .eq(ProductionPlan::getSalesLedgerProductId, productId)); } /** * 通用方法:根据主表ID和子表列表,更新主表的合同金额 */ public <T, S> void updateMainContractAmount( src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -800,4 +800,16 @@ result.put("ledger", ledger); return result; } @Override public Map<Long, SalesLedgerEditFlagDto> getEditFlags(List<Long> ids) { if (CollectionUtils.isEmpty(ids)) { return new HashMap<>(); } List<SalesLedgerEditFlagDto> flags = salesLedgerMapper.selectEditFlags(ids); return flags.stream().collect(Collectors.toMap( SalesLedgerEditFlagDto::getSalesLedgerId, Function.identity(), (existing, replacement) -> existing)); } } src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -147,6 +147,22 @@ order by sl.execution_date desc </select> <select id="selectEditFlags" resultType="com.ruoyi.sales.dto.SalesLedgerEditFlagDto"> SELECT T1.id AS salesLedgerId, MAX(CASE WHEN T2.is_production = 1 THEN 1 ELSE 0 END) AS needsProduction, MAX(CASE WHEN T3.status IS NOT NULL AND T3.status <> 0 THEN 1 ELSE 0 END) AS planIssued, MAX(CASE WHEN T4.status IN ('审核通过', '已发货') THEN 1 ELSE 0 END) AS shipped FROM sales_ledger T1 LEFT JOIN sales_ledger_product T2 ON T2.sales_ledger_id = T1.id AND T2.type = 1 LEFT JOIN production_plan T3 ON T3.sales_ledger_product_id = T2.id LEFT JOIN shipping_info T4 ON T4.sales_ledger_product_id = T2.id WHERE T1.id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> GROUP BY T1.id </select> <select id="selectPurchaseReportVoPage" resultType="com.ruoyi.purchase.vo.PurchaseReportVo"> select sl.sales_contract_no customerContractNo, c.customer_name,