| | |
| | | import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; |
| | | import com.ruoyi.basic.enums.ApplicationTypeEnum; |
| | | import com.ruoyi.basic.enums.RecordTypeEnum; |
| | | import com.ruoyi.basic.mapper.OilDepotMapper; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.mapper.SupplierManageMapper; |
| | | import com.ruoyi.basic.pojo.OilDepot; |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.basic.pojo.SupplierManage; |
| | |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.measuringinstrumentledger.mapper.SparePartsMapper; |
| | | import com.ruoyi.measuringinstrumentledger.pojo.SpareParts; |
| | | import com.ruoyi.measuringinstrumentledger.pojo.SparePartsRecord; |
| | | import com.ruoyi.measuringinstrumentledger.service.SparePartsRecordService; |
| | | import com.ruoyi.other.mapper.TempFileMapper; |
| | | import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage; |
| | |
| | | @RequiredArgsConstructor |
| | | public class PurchaseLedgerServiceImpl extends ServiceImpl<PurchaseLedgerMapper, PurchaseLedger> implements IPurchaseLedgerService { |
| | | |
| | | /** |
| | | * 明细类型:采购(sales_ledger_product.type)。仅采购明细才回写备件库存 |
| | | */ |
| | | private static final Integer LEDGER_TYPE_PURCHASE = 2; |
| | | |
| | | /** |
| | | * 备件流水来源:采购入库。见 spare_parts_record.source_type |
| | | */ |
| | | private static final Integer SPARE_PARTS_SOURCE_PURCHASE = 1; |
| | | |
| | | private final PurchaseLedgerMapper purchaseLedgerMapper; |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | private final SalesLedgerProductMapper salesLedgerProductMapper; |
| | |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockUtils stockUtils; |
| | | private final ApprovalTemplateMapper approvalTemplateMapper; |
| | | private final OilDepotMapper oilDepotMapper; |
| | | private final SparePartsMapper sparePartsMapper; |
| | | private final SparePartsRecordService sparePartsRecordService; |
| | | |
| | | @Override |
| | | public List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger) { |
| | |
| | | purchaseLedger.setSupplierName(supplierManage.getSupplierName()); |
| | | purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); |
| | | |
| | | // 采购油库:根据油库id回填油库名称 |
| | | if (purchaseLedgerDto.getOilDepotId() != null) { |
| | | OilDepot oilDepot = oilDepotMapper.selectById(purchaseLedgerDto.getOilDepotId()); |
| | | if (oilDepot != null) { |
| | | purchaseLedger.setOilDepotName(oilDepot.getDepotName()); |
| | | } |
| | | } |
| | | |
| | | purchaseLedger.setApprovalStatus(1); |
| | | // 实际合同金额始终等于合同金额 |
| | | purchaseLedger.setNetContractAmount(purchaseLedger.getContractAmount()); |
| | |
| | | purchaseLedger.setPurchaseContractNumber(generatePurchaseContractNo(purchaseLedger.getEntryDate())); |
| | | } |
| | | this.saveOrUpdate(purchaseLedger); |
| | | // 回写主键,供调用方(如采购申请转订单)获取新生成的采购台账id |
| | | purchaseLedgerDto.setId(purchaseLedger.getId()); |
| | | |
| | | // 4. 处理子表数据 |
| | | List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData(); |
| | |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | } |
| | | } |
| | | // 采购明细回写备件:先按台账回滚上一次的流水,再按当前明细整体重建。 |
| | | // 编辑时明细行可能被移除,只认新增行会漏掉移除的那些;整体重建天然与当前明细对齐。 |
| | | // 注意这段必须在 insertList 之外,否则「只删明细、不新增」的编辑不会触发回滚 |
| | | if (LEDGER_TYPE_PURCHASE.equals(ledgerType)) { |
| | | rollbackSparePartsInbound(salesLedgerId); |
| | | recordSparePartsInbound(products, purchaseLedger); |
| | | } |
| | | |
| | | // 计算总含税金额 |
| | | BigDecimal totalTaxInclusiveAmount = products.stream() |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 按采购台账回滚备件:把该台账产生的入库流水逐备件减回库存,然后删除这些流水。 |
| | | * |
| | | * <p>备件先由采购入账、后续被维修/保养领用出账,若入账量已经被领用掉,减回会出现负库存, |
| | | * 此时直接拦住不让删,避免把备件账做花。删除台账与编辑重建都走这里,口径统一。</p> |
| | | */ |
| | | private void rollbackSparePartsInbound(Long ledgerId) { |
| | | List<SparePartsRecord> records = sparePartsRecordService.list(new LambdaQueryWrapper<SparePartsRecord>() |
| | | .eq(SparePartsRecord::getSourceType, SPARE_PARTS_SOURCE_PURCHASE) |
| | | .eq(SparePartsRecord::getSourceId, ledgerId)); |
| | | if (CollectionUtils.isEmpty(records)) { |
| | | return; |
| | | } |
| | | Map<Long, BigDecimal> rollbackBySparePartsId = new HashMap<>(); |
| | | for (SparePartsRecord record : records) { |
| | | BigDecimal quantity = record.getQuantity() == null ? BigDecimal.ZERO : record.getQuantity(); |
| | | rollbackBySparePartsId.merge(record.getSparePartsId(), quantity, BigDecimal::add); |
| | | } |
| | | for (Map.Entry<Long, BigDecimal> entry : rollbackBySparePartsId.entrySet()) { |
| | | if (entry.getKey() == null) { |
| | | continue; |
| | | } |
| | | SpareParts spareParts = sparePartsMapper.selectById(entry.getKey()); |
| | | if (spareParts == null) { |
| | | continue; |
| | | } |
| | | BigDecimal current = spareParts.getQuantity() == null ? BigDecimal.ZERO : spareParts.getQuantity(); |
| | | if (current.compareTo(entry.getValue()) < 0) { |
| | | throw new BaseException("备件「" + spareParts.getName() + "」当前库存 " + current |
| | | + ",不足以回滚本次采购入库的 " + entry.getValue() + ",请先处理领用记录"); |
| | | } |
| | | spareParts.setQuantity(current.subtract(entry.getValue())); |
| | | sparePartsMapper.updateById(spareParts); |
| | | } |
| | | sparePartsRecordService.removeByIds(records.stream() |
| | | .map(SparePartsRecord::getId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList())); |
| | | } |
| | | |
| | | /** |
| | | * 采购台账明细按规格匹配备件:累加备件库存并记一条入库流水。 |
| | | * 未维护规格的备件不参与,静默跳过。 |
| | | * |
| | | * <p>调用前必须先 {@link #rollbackSparePartsInbound(Long)},两者成对出现: |
| | | * 回滚旧流水 + 按当前明细重建,才能保证编辑台账后备件数量与明细一致。</p> |
| | | */ |
| | | private void recordSparePartsInbound(List<SalesLedgerProduct> products, PurchaseLedger purchaseLedger) { |
| | | List<Long> modelIds = products.stream() |
| | | .map(SalesLedgerProduct::getProductModelId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | if (modelIds.isEmpty()) { |
| | | return; |
| | | } |
| | | List<SpareParts> sparePartsList = sparePartsMapper.selectList(new LambdaQueryWrapper<SpareParts>() |
| | | .in(SpareParts::getProductModelId, modelIds)); |
| | | if (CollectionUtils.isEmpty(sparePartsList)) { |
| | | return; |
| | | } |
| | | Map<Long, SpareParts> sparePartsByModelId = sparePartsList.stream() |
| | | .collect(Collectors.toMap(SpareParts::getProductModelId, s -> s, (a, b) -> a)); |
| | | for (SalesLedgerProduct product : products) { |
| | | SpareParts spareParts = sparePartsByModelId.get(product.getProductModelId()); |
| | | if (spareParts == null || product.getQuantity() == null |
| | | || product.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | BigDecimal quantity = product.getQuantity(); |
| | | spareParts.setQuantity((spareParts.getQuantity() == null ? BigDecimal.ZERO : spareParts.getQuantity()).add(quantity)); |
| | | sparePartsMapper.updateById(spareParts); |
| | | |
| | | SparePartsRecord record = new SparePartsRecord(); |
| | | record.setSparePartsId(spareParts.getId()); |
| | | record.setDirection(1); |
| | | record.setQuantity(quantity); |
| | | record.setSourceType(1); |
| | | record.setSourceId(purchaseLedger.getId()); |
| | | record.setSourceNo(purchaseLedger.getPurchaseContractNumber()); |
| | | sparePartsRecordService.save(record); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int deletePurchaseLedgerByIds(Long[] ids) { |
| | |
| | | if (purchaseLedger.getApprovalStatus().equals(3)) { |
| | | throw new BaseException(purchaseLedger.getPurchaseContractNumber()+"已经审批通过,不允许删除"); |
| | | } |
| | | // 台账删除要把该台账采购入库时累加到备件上的数量减回去,并删掉对应流水, |
| | | // 否则备件库存虚高、流水残留。备件已领用导致减回为负时会在这里拦住 |
| | | rollbackSparePartsInbound(id); |
| | | } |
| | | // 批量删除关联的采购入库记录 |
| | | LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductQueryWrapper = new LambdaQueryWrapper<>(); |