package com.ruoyi.purchase.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.ApprovalInstanceService; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.enums.ApprovalStatusEnum; import com.ruoyi.common.enums.ReviewStatusEnum; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.framework.web.domain.R; import com.ruoyi.other.mapper.TempFileMapper; import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper; import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.purchase.dto.PurchaseLedgerDto; import com.ruoyi.purchase.dto.PurchaseLedgerImportDto; import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto; import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.mapper.QualityInspectParamMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; import com.ruoyi.quality.mapper.QualityTestStandardParamMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityInspectParam; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardParam; import com.ruoyi.quality.service.IQualityInspectService; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.impl.CommonFileServiceImpl; import com.ruoyi.stock.pojo.StockInRecord; import com.ruoyi.stock.service.StockInRecordService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * 采购台账Service业务层处理 * * @author ruoyi * @date 2025-05-09 */ @Service @Slf4j @RequiredArgsConstructor public class PurchaseLedgerServiceImpl extends ServiceImpl implements IPurchaseLedgerService { private final PurchaseLedgerMapper purchaseLedgerMapper; private final SalesLedgerMapper salesLedgerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final SysUserMapper userMapper; private final TempFileMapper tempFileMapper; private final CommonFileMapper commonFileMapper; private final SupplierManageMapper supplierManageMapper; private final ProductMapper productMapper; private final ProductModelMapper productModelMapper; private final SysUserMapper sysUserMapper; private final StringRedisTemplate redisTemplate; private final QualityInspectMapper qualityInspectMapper; private final CommonFileServiceImpl commonFileService; private final QualityTestStandardParamMapper qualityTestStandardParamMapper; private final QualityTestStandardMapper qualityTestStandardMapper; private final QualityInspectParamMapper qualityInspectParamMapper; private final ApproveProcessServiceImpl approveProcessService; private final ProcurementRecordMapper procurementRecordStorageMapper; private final FileUtil fileUtil; private final ApprovalInstanceService approvalInstanceService; private final IQualityInspectService qualityInspectService; private final StockInRecordService stockInRecordService; private final StockUtils stockUtils; private final ApprovalTemplateMapper approvalTemplateMapper; @Override public List selectPurchaseLedgerList(PurchaseLedger purchaseLedger) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StringUtils.isNotBlank(purchaseLedger.getPurchaseContractNumber())) { queryWrapper.like(PurchaseLedger::getPurchaseContractNumber, purchaseLedger.getPurchaseContractNumber()); } if(purchaseLedger.getSupplierId()!=null){ queryWrapper.eq(PurchaseLedger::getSupplierId, purchaseLedger.getSupplierId()); } if (purchaseLedger.getApprovalStatus() != null) { queryWrapper.eq(PurchaseLedger::getApprovalStatus, purchaseLedger.getApprovalStatus()); } return purchaseLedgerMapper.selectList(queryWrapper); } @Override @Transactional(rollbackFor = Exception.class) public int addOrEditPurchase(PurchaseLedgerDto purchaseLedgerDto) throws Exception { PurchaseLedger purchaseLedger = new PurchaseLedger(); // DTO转Entity BeanUtils.copyProperties(purchaseLedgerDto, purchaseLedger); SalesLedger salesLedger = salesLedgerMapper.selectById(purchaseLedgerDto.getSalesLedgerId()); //录入人 SysUser sysUser = userMapper.selectUserById(purchaseLedgerDto.getRecorderId()); if (ObjectUtils.isNotEmpty(sysUser)) { purchaseLedger.setRecorderName(sysUser.getNickName()); purchaseLedger.setPhoneNumber(sysUser.getPhonenumber()); }else { purchaseLedger.setRecorderName(SecurityUtils.getLoginUser().getNickName()); SysUser sysUser1 = userMapper.selectUserById(SecurityUtils.getUserId()); purchaseLedger.setPhoneNumber(sysUser1.getPhonenumber()); } SupplierManage supplierManage = supplierManageMapper.selectById(purchaseLedgerDto.getSupplierId()); LoginUser loginUser = SecurityUtils.getLoginUser(); if (ObjectUtils.isNotEmpty(loginUser) && null != loginUser.getTenantId()) { purchaseLedger.setTenantId(loginUser.getTenantId()); } purchaseLedger.setSalesContractNo(ObjectUtils.isNotEmpty(salesLedger) ? salesLedger.getSalesContractNo() : ""); purchaseLedger.setSalesLedgerId(ObjectUtils.isNotEmpty(salesLedger) ? salesLedger.getId() : -1); purchaseLedger.setSupplierName(supplierManage.getSupplierName()); purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); purchaseLedger.setApprovalStatus(1); // 3. 新增或更新主表 if (purchaseLedger.getId() == null) { purchaseLedgerMapper.insert(purchaseLedger); } else { // 删除采购审核,重新提交 ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper() .eq(ApproveProcess::getApproveType, 5) .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber()) .eq(ApproveProcess::getApproveDelete, 0) .last("limit 1")); if (one != null) { approveProcessService.delByIds(Collections.singletonList(one.getId())); } purchaseLedgerMapper.updateById(purchaseLedger); } // 4. 处理子表数据 List productList = purchaseLedgerDto.getProductData(); if (productList != null && !productList.isEmpty()) { handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType()); } // 6.采购审核新增;审批管理未配置采购审批人时,审批服务会自动置为审批通过。 addApproveByPurchase(loginUser, purchaseLedger); // 5. 迁移临时文件到正式目录 fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId(), purchaseLedgerDto.getStorageBlobDTOS()); return 1; } @Override public R batchInsertPurchaseSteps(List ids) { if (CollectionUtils.isEmpty(ids)) { return R.fail("请选择采购台账"); } List distinctIds = ids.stream() .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (CollectionUtils.isEmpty(distinctIds)) { return R.fail("请选择采购台账"); } PurchaseLedgerDto queryDto = new PurchaseLedgerDto(); queryDto.setIds(distinctIds); IPage pageResult = this.selectPurchaseLedgerListPage( new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(1, distinctIds.size()), queryDto ); List ledgerDtos = pageResult == null || pageResult.getRecords() == null ? Collections.emptyList() : pageResult.getRecords(); Map ledgerDtoMap = ledgerDtos.stream() .filter(item -> item.getId() != null) .collect(Collectors.toMap(PurchaseLedgerDto::getId, item -> item, (left, right) -> left, LinkedHashMap::new)); List> details = new ArrayList<>(); int successCount = 0; int skipCount = 0; int failCount = 0; int autoApprovedCount = 0; for (Long id : distinctIds) { Map detail = new LinkedHashMap<>(); detail.put("purchaseLedgerId", id); PurchaseLedgerDto purchaseLedgerDto = ledgerDtoMap.get(id); if (purchaseLedgerDto == null) { failCount++; detail.put("status", "FAIL"); detail.put("message", "采购台账不存在或未查询到"); details.add(detail); continue; } detail.put("purchaseContractNumber", purchaseLedgerDto.getPurchaseContractNumber()); detail.put("approvalStatus", purchaseLedgerDto.getApprovalStatus()); detail.put("stockInStatus", purchaseLedgerDto.getStockInStatus()); if (ApprovalStatusEnum.REJECTED.getCode().equals(purchaseLedgerDto.getApprovalStatus())) { skipCount++; detail.put("status", "SKIP"); detail.put("message", "采购单已驳回"); details.add(detail); continue; } if ("完全入库".equals(purchaseLedgerDto.getStockInStatus())) { skipCount++; detail.put("status", "SKIP"); detail.put("message", "采购单已完全入库"); details.add(detail); continue; } try { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); if (purchaseLedger == null) { failCount++; detail.put("status", "FAIL"); detail.put("message", "采购台账不存在"); details.add(detail); continue; } if (!ApprovalStatusEnum.APPROVED.getCode().equals(purchaseLedger.getApprovalStatus())) { ApprovalInstance approvalInstance = approvalInstanceService.getOne( Wrappers.lambdaQuery() .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId()) .eq(ApprovalInstance::getBusinessType, 5L) .eq(ApprovalInstance::getDeleted, 0) .orderByDesc(ApprovalInstance::getId) .last("limit 1") ); if (approvalInstance == null) { failCount++; detail.put("status", "FAIL"); detail.put("message", "未找到对应的采购审批实例"); details.add(detail); continue; } if ("APPROVED".equals(approvalInstance.getStatus()) && !ApprovalStatusEnum.APPROVED.getCode().equals(purchaseLedger.getApprovalStatus())) { purchaseLedger.setApprovalStatus(ApprovalStatusEnum.APPROVED.getCode()); purchaseLedgerMapper.updateById(purchaseLedger); } else if (!"APPROVED".equals(approvalInstance.getStatus())) { R autoApproveResult = approvalInstanceService.autoApprove(approvalInstance.getId()); if (autoApproveResult == null || !R.isSuccess(autoApproveResult)) { failCount++; detail.put("status", "FAIL"); detail.put("message", autoApproveResult == null ? "采购审批自动通过失败" : autoApproveResult.getMsg()); details.add(detail); continue; } autoApprovedCount++; } purchaseLedger = purchaseLedgerMapper.selectById(id); if (purchaseLedger == null || !ApprovalStatusEnum.APPROVED.getCode().equals(purchaseLedger.getApprovalStatus())) { failCount++; detail.put("status", "FAIL"); detail.put("message", "采购单审批状态未更新为已通过"); details.add(detail); continue; } } List products = salesLedgerProductMapper.selectList( Wrappers.lambdaQuery() .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, 2) .orderByAsc(SalesLedgerProduct::getId) ); if (CollectionUtils.isEmpty(products)) { skipCount++; detail.put("status", "SKIP"); detail.put("message", "采购单没有产品明细"); details.add(detail); continue; } int processedProductCount = 0; int skippedProductCount = 0; int failedProductCount = 0; for (SalesLedgerProduct product : products) { try { boolean processed; if (Boolean.TRUE.equals(product.getIsChecked())) { processed = processPurchaseQualityProduct(purchaseLedger, product); } else { processed = processPurchaseDirectProduct(purchaseLedger, product); } if (processed) { processedProductCount++; } else { skippedProductCount++; } } catch (Exception ex) { failedProductCount++; log.error("批量推进采购台账失败, purchaseLedgerId={}, productId={}, productModelId={}", purchaseLedger.getId(), product.getId(), product.getProductModelId(), ex); } } successCount++; detail.put("status", failedProductCount > 0 ? "PARTIAL" : "SUCCESS"); detail.put("processedProductCount", processedProductCount); detail.put("skippedProductCount", skippedProductCount); detail.put("failedProductCount", failedProductCount); detail.put("message", failedProductCount > 0 ? "部分产品处理失败" : "处理完成"); details.add(detail); } catch (Exception ex) { failCount++; detail.put("status", "FAIL"); detail.put("message", ex.getMessage()); details.add(detail); log.error("批量推进采购台账失败, purchaseLedgerId={}", id, ex); } } Map summary = new LinkedHashMap<>(); summary.put("totalCount", distinctIds.size()); summary.put("successCount", successCount); summary.put("skipCount", skipCount); summary.put("failCount", failCount); summary.put("autoApprovedCount", autoApprovedCount); summary.put("details", details); return R.ok(summary, "批量推进采购步骤完成"); } public void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) { QualityInspect qualityInspect = new QualityInspect(); qualityInspect.setInspectType(0); qualityInspect.setSupplier(purchaseLedger.getSupplierName()); qualityInspect.setPurchaseLedgerId(purchaseLedger.getId()); qualityInspect.setProductId(saleProduct.getProductId()); qualityInspect.setProductName(saleProduct.getProductCategory()); qualityInspect.setModel(saleProduct.getSpecificationModel()); qualityInspect.setProductModelId(saleProduct.getProductModelId()); qualityInspect.setUnit(saleProduct.getUnit()); qualityInspect.setQuantity(saleProduct.getQuantity()); qualityInspectMapper.insert(qualityInspect); List qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0,null); if (qualityTestStandard.size()>0){ qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId,qualityTestStandard.get(0).getId())) .forEach(qualityTestStandardParam -> { QualityInspectParam param = new QualityInspectParam(); com.ruoyi.common.utils.bean.BeanUtils.copyProperties(qualityTestStandardParam, param); param.setId(null); param.setInspectId(qualityInspect.getId()); qualityInspectParamMapper.insert(param); }); } } private boolean processPurchaseQualityProduct(PurchaseLedger purchaseLedger, SalesLedgerProduct product) { if (purchaseLedger == null || product == null || product.getProductModelId() == null) { return false; } QualityInspect qualityInspect = findLatestPurchaseQualityInspect(purchaseLedger.getId(), product.getProductModelId()); if (qualityInspect == null) { addQualityInspect(purchaseLedger, product); qualityInspect = findLatestPurchaseQualityInspect(purchaseLedger.getId(), product.getProductModelId()); } if (qualityInspect == null) { return false; } LocalDateTime purchaseInspectTime = toStartOfDayPlusDays(purchaseLedger.getEntryDate(), 1); if (purchaseInspectTime != null && (qualityInspect.getCheckTime() == null || !DateUtils.toLocalDate(qualityInspect.getCheckTime()).equals(purchaseInspectTime.toLocalDate()))) { qualityInspect.setCheckTime(DateUtils.toDate(purchaseInspectTime.toLocalDate())); qualityInspectMapper.updateById(qualityInspect); } List stockRecords = findQualityStockRecords(qualityInspect.getId(), product.getProductModelId()); if (hasApprovedStockRecord(stockRecords)) { return true; } if (!Integer.valueOf(1).equals(qualityInspect.getInspectState())) { R autoSubmitResult = qualityInspectService.autoSubmit(qualityInspect.getId()); if (autoSubmitResult == null || !R.isSuccess(autoSubmitResult)) { return false; } qualityInspect = qualityInspectMapper.selectById(qualityInspect.getId()); } stockRecords = findQualityStockRecords(qualityInspect.getId(), product.getProductModelId()); if (CollectionUtils.isEmpty(stockRecords) && qualityInspect.getQualifiedQuantity() != null && qualityInspect.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) { stockUtils.addStockWithBatchNo( product.getProductModelId(), qualityInspect.getQualifiedQuantity(), StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode(), qualityInspect.getId(), null, purchaseInspectTime == null ? null : purchaseInspectTime.plusDays(1) ); stockRecords = findQualityStockRecords(qualityInspect.getId(), product.getProductModelId()); } StockInRecord targetStockRecord = findLatestUnapprovedStockRecord(stockRecords); if (targetStockRecord == null) { return false; } LocalDateTime qualityStockCreateTime = resolveQualityStockCreateTime(qualityInspect); if (qualityStockCreateTime != null && (targetStockRecord.getCreateTime() == null || !qualityStockCreateTime.equals(targetStockRecord.getCreateTime()))) { targetStockRecord.setCreateTime(qualityStockCreateTime); stockInRecordService.updateById(targetStockRecord); } approveStockRecords(Collections.singletonList(targetStockRecord)); stockRecords = findQualityStockRecords(qualityInspect.getId(), product.getProductModelId()); return hasApprovedStockRecord(stockRecords); } private boolean processPurchaseDirectProduct(PurchaseLedger purchaseLedger, SalesLedgerProduct product) { if (purchaseLedger == null || product == null || product.getProductModelId() == null) { return false; } if (product.getQuantity() == null) { return false; } if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) { return false; } LocalDateTime stockCreateTime = toStartOfDayPlusDays(purchaseLedger.getEntryDate(), 1); List stockRecords = findDirectStockRecords(purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber(), product.getProductModelId(), product.getId()); if (hasApprovedStockRecord(stockRecords)) { return true; } if (CollectionUtils.isEmpty(stockRecords)) { stockUtils.addStockWithBatchNo( product.getProductModelId(), product.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber() + "-" + product.getId(), stockCreateTime ); stockRecords = findDirectStockRecords(purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber(), product.getProductModelId(), product.getId()); } if (CollectionUtils.isEmpty(stockRecords)) { return false; } StockInRecord targetStockRecord = findLatestUnapprovedStockRecord(stockRecords); if (targetStockRecord == null) { return false; } if (stockCreateTime != null && (targetStockRecord.getCreateTime() == null || !stockCreateTime.equals(targetStockRecord.getCreateTime()))) { targetStockRecord.setCreateTime(stockCreateTime); stockInRecordService.updateById(targetStockRecord); } approveStockRecords(Collections.singletonList(targetStockRecord)); stockRecords = findDirectStockRecords(purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber(), product.getProductModelId(), product.getId()); return hasApprovedStockRecord(stockRecords); } private LocalDateTime toStartOfDayPlusDays(Date date, int days) { if (date == null) { return null; } return DateUtils.toLocalDate(date).plusDays(days).atStartOfDay(); } private LocalDateTime resolveQualityStockCreateTime(QualityInspect qualityInspect) { if (qualityInspect == null || qualityInspect.getCheckTime() == null) { return null; } return DateUtils.toLocalDate(qualityInspect.getCheckTime()).plusDays(1).atStartOfDay(); } private QualityInspect findLatestPurchaseQualityInspect(Long purchaseLedgerId, Long productModelId) { if (purchaseLedgerId == null || productModelId == null) { return null; } return qualityInspectMapper.selectOne( Wrappers.lambdaQuery() .eq(QualityInspect::getInspectType, 0) .eq(QualityInspect::getPurchaseLedgerId, purchaseLedgerId) .eq(QualityInspect::getProductModelId, productModelId) .orderByDesc(QualityInspect::getId) .last("limit 1") ); } private List findQualityStockRecords(Long qualityInspectId, Long productModelId) { if (qualityInspectId == null || productModelId == null) { return Collections.emptyList(); } return stockInRecordService.list( Wrappers.lambdaQuery() .eq(StockInRecord::getRecordType, StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()) .eq(StockInRecord::getRecordId, qualityInspectId) .eq(StockInRecord::getProductModelId, productModelId) .orderByDesc(StockInRecord::getId) ); } private List findDirectStockRecords(Long purchaseLedgerId, String purchaseContractNumber, Long productModelId, Long purchaseProductId) { if (purchaseLedgerId == null || productModelId == null || purchaseProductId == null || !StringUtils.hasText(purchaseContractNumber)) { return Collections.emptyList(); } String batchNo = purchaseContractNumber + "-" + purchaseProductId; return stockInRecordService.list( Wrappers.lambdaQuery() .eq(StockInRecord::getRecordType, StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode()) .eq(StockInRecord::getRecordId, purchaseLedgerId) .eq(StockInRecord::getProductModelId, productModelId) .eq(StockInRecord::getBatchNo, batchNo) .orderByDesc(StockInRecord::getId) ); } private boolean hasApprovedStockRecord(List stockRecords) { return stockRecords != null && stockRecords.stream() .anyMatch(item -> ReviewStatusEnum.APPROVED.getCode().equals(item.getApprovalStatus())); } private StockInRecord findLatestUnapprovedStockRecord(List stockRecords) { if (CollectionUtils.isEmpty(stockRecords)) { return null; } return stockRecords.stream() .filter(item -> !ReviewStatusEnum.APPROVED.getCode().equals(item.getApprovalStatus())) .findFirst() .orElse(null); } private void approveStockRecords(List stockRecords) { if (CollectionUtils.isEmpty(stockRecords)) { return; } List rejectedIds = stockRecords.stream() .filter(item -> ReviewStatusEnum.REJECTED.getCode().equals(item.getApprovalStatus())) .map(StockInRecord::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); if (!rejectedIds.isEmpty()) { stockInRecordService.batchReAudit(rejectedIds); } List pendingIds = stockRecords.stream() .filter(item -> item.getApprovalStatus() == null || ReviewStatusEnum.PENDING_REVIEW.getCode().equals(item.getApprovalStatus()) || ReviewStatusEnum.REJECTED.getCode().equals(item.getApprovalStatus())) .map(StockInRecord::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); if (!pendingIds.isEmpty()) { stockInRecordService.batchApprove(pendingIds, ReviewStatusEnum.APPROVED.getCode()); } } private void handleSalesLedgerProducts(Long salesLedgerId, List products, Integer type) { if (products == null || products.isEmpty()) { throw new BaseException("产品信息不存在"); } Integer ledgerType = type == null ? 2 : type; // 提前收集所有需要查询的ID Set productIds = products.stream() .map(SalesLedgerProduct::getProductId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Set modelIds = products.stream() .map(SalesLedgerProduct::getProductModelId) .filter(Objects::nonNull) .collect(Collectors.toSet()); // 一次性查询产品和型号信息 Map productMap = new HashMap<>(); if (!productIds.isEmpty()) { List productList = productMapper.selectBatchIds(productIds); productList.forEach(p -> productMap.put(p.getId(), p.getProductName())); } Map modelMap = new HashMap<>(); if (!modelIds.isEmpty()) { List modelList = productModelMapper.selectBatchIds(modelIds); modelList.forEach(m -> modelMap.put(m.getId(), m.getModel())); } // 设置字段 for (SalesLedgerProduct product : products) { product.setSalesLedgerId(salesLedgerId); Long productId = product.getProductId(); if (productId != null && productMap.containsKey(productId)) { product.setProductCategory(productMap.get(productId)); } Long productModelId = product.getProductModelId(); if (productModelId != null && modelMap.containsKey(productModelId)) { product.setSpecificationModel(modelMap.get(productModelId)); } } // 分组处理 Map> partitionedProducts = products.stream() .collect(Collectors.partitioningBy(p -> p.getId() != null)); List updateList = partitionedProducts.get(true); List insertList = partitionedProducts.get(false); PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(salesLedgerId); // 执行更新操作 if (!updateList.isEmpty()) { for (SalesLedgerProduct product : updateList) { product.setType(ledgerType); salesLedgerProductMapper.updateById(product); } } // 执行插入操作 if (!insertList.isEmpty()) { for (SalesLedgerProduct salesLedgerProduct : insertList) { salesLedgerProduct.setType(ledgerType); Date entryDate = purchaseLedger.getEntryDate(); LocalDateTime localDateTime = entryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); salesLedgerProduct.setRegisterDate(localDateTime); salesLedgerProductMapper.insert(salesLedgerProduct); } } // 计算总含税金额 BigDecimal totalTaxInclusiveAmount = products.stream() .map(SalesLedgerProduct::getTaxInclusiveTotalPrice) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); // 更新主表的总金额字段 if (salesLedgerId != null) { // 直接更新指定ID的记录的contractAmount字段为totalTaxInclusiveAmount purchaseLedgerMapper.updateContractAmountById(salesLedgerId, totalTaxInclusiveAmount); } } @Override @Transactional(rollbackFor = Exception.class) public int deletePurchaseLedgerByIds(Long[] ids) { if (ids == null || ids.length == 0) { throw new BaseException("请选中至少一条数据"); } for (Long id : ids) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); if (purchaseLedger.getApprovalStatus().equals(3)) { throw new BaseException(purchaseLedger.getPurchaseContractNumber()+"已经审批通过,不允许删除"); } } // 批量删除关联的采购入库记录 LambdaQueryWrapper salesLedgerProductQueryWrapper = new LambdaQueryWrapper<>(); salesLedgerProductQueryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids) .eq(SalesLedgerProduct::getType, 2); List salesLedgerProducts = salesLedgerProductMapper.selectList(salesLedgerProductQueryWrapper); if (CollectionUtils.isNotEmpty(salesLedgerProducts)) { salesLedgerProducts.stream().forEach(salesLedgerProduct -> { // 批量删除关联的采购台账产品 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ProcurementRecordStorage::getSalesLedgerProductId, salesLedgerProduct.getId()); procurementRecordStorageMapper.delete(queryWrapper); }); } // 批量删除关联的采购台账产品 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids) .eq(SalesLedgerProduct::getType, 2); salesLedgerProductMapper.delete(queryWrapper); //批量删除检验标准 LambdaQueryWrapper materialInspectLambdaQueryWrapper = new LambdaQueryWrapper<>(); materialInspectLambdaQueryWrapper.in(QualityInspect::getPurchaseLedgerId, ids); List qualityInspects = qualityInspectMapper.selectList(materialInspectLambdaQueryWrapper); qualityInspects.stream().forEach(qualityInspect -> { if (ObjectUtils.isNotEmpty(qualityInspect.getInspectState())&&qualityInspect.getInspectState().equals(1)) { throw new BaseException("已提交的检验单不能删除"); } }); List inspectIds = qualityInspects.stream() .map(QualityInspect::getId) .collect(Collectors.toList()); if (inspectIds.size() > 0) { LambdaQueryWrapper qualityStandardLambdaQueryWrapper = new LambdaQueryWrapper<>(); qualityStandardLambdaQueryWrapper.in(QualityInspectParam::getInspectId, inspectIds); qualityInspectParamMapper.delete(qualityStandardLambdaQueryWrapper); } // 删除采购审批记录 for (Long id : ids) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); if(purchaseLedger != null){ ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper() .eq(ApproveProcess::getApproveType, 5) .eq(ApproveProcess::getApproveDelete, 0) .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber()) .last("limit 1")); if (one != null) { approveProcessService.delByIds(Collections.singletonList(one.getId())); } } } //批量删除原材料检验数据 qualityInspectMapper.delete(materialInspectLambdaQueryWrapper); //删除附件 commonFileService.deleteByBusinessIds(Arrays.asList(ids), 2); // 批量删除采购台账 return purchaseLedgerMapper.deleteBatchIds(Arrays.asList(ids)); } @Override public PurchaseLedgerDto getPurchaseById(PurchaseLedgerDto purchaseLedgerDto) { // 1. 查询主表 PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseLedgerDto.getId()); if (purchaseLedger == null) { throw new BaseException("采购台账不存在"); } // 2. 查询子表 LambdaQueryWrapper productWrapper = new LambdaQueryWrapper<>(); productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, purchaseLedgerDto.getType()); List products = salesLedgerProductMapper.selectList(productWrapper); // 4. 转换 DTO PurchaseLedgerDto resultDto = new PurchaseLedgerDto(); BeanUtils.copyProperties(purchaseLedger, resultDto); if (!products.isEmpty()) { resultDto.setHasChildren(true); resultDto.setProductData(products); resultDto.setStorageBlobVOS(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId())); } return resultDto; } @Override public List getProduct(PurchaseLedgerDto purchaseLedgerDto) { LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); queryWrapper.select(PurchaseLedger::getId, PurchaseLedger::getPurchaseContractNumber); // 获取原始查询结果 List> result = purchaseLedgerMapper.selectMaps(queryWrapper); // 将下划线命名转换为驼峰命名 return result.stream().map(map -> map.entrySet().stream() .collect(Collectors.toMap( entry -> underlineToCamel(entry.getKey()), Map.Entry::getValue)) ).collect(Collectors.toList()); } @Override public PurchaseLedgerDto getInfo(PurchaseLedgerDto purchaseLedgerDto) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseLedgerDto.getId()); if (purchaseLedger == null) { throw new BaseException("采购台账不存在"); } // 创建并填充DTO PurchaseLedgerDto resultDto = new PurchaseLedgerDto(); resultDto.setSalesLedgerId(purchaseLedger.getSalesLedgerId()); resultDto.setSalesContractNoId(purchaseLedger.getSalesLedgerId()); resultDto.setSalesContractNo(purchaseLedger.getSalesContractNo()); resultDto.setSupplierName(purchaseLedger.getSupplierName()); resultDto.setProjectName(purchaseLedger.getProjectName()); // 查询并设置关联产品 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, 2); List productList = salesLedgerProductMapper.selectList(queryWrapper); resultDto.setProductData(productList); return resultDto; } @Override public List getPurchasesNo() { LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); queryWrapper.select(PurchaseLedger::getId, PurchaseLedger::getPurchaseContractNumber, PurchaseLedger::getSupplierId); // 获取原始查询结果 List> result = purchaseLedgerMapper.selectMaps(queryWrapper); // 将下划线命名转换为驼峰命名 return result.stream().map(map -> map.entrySet().stream() .collect(Collectors.toMap( entry -> underlineToCamel(entry.getKey()), Map.Entry::getValue)) ).collect(Collectors.toList()); } @Override public PurchaseLedgerDto getPurchaseNoById(Long id) { PurchaseLedgerDto purchaseLedgerDto = new PurchaseLedgerDto(); PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); BeanUtils.copyProperties(purchaseLedger, purchaseLedgerDto); return purchaseLedgerDto; } @Override public IPage selectPurchaseLedgerListPage(IPage ipage, PurchaseLedgerDto purchaseLedger) { return purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger); } @Override public String getPurchaseNo(Date entryDate) { LocalDate localDate = entryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); // 生成日期前缀(例如:CG20250405) String purchaseNo = "CG" + localDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 构建 Redis Key(按天分隔) String redisKey = "purchase_no:" + localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); // 获取当前序号并递增(原子操作) Long sequence = redisTemplate.opsForValue().increment(redisKey); // 设置过期时间(次日失效,防止冗余数据) if (sequence == 1) { redisTemplate.expire(redisKey, 1, TimeUnit.DAYS); } // 返回完整编号(如 CG202504050001) return purchaseNo + String.format("%03d", sequence); } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult importData(MultipartFile file) { LoginUser loginUser = SecurityUtils.getLoginUser(); try { InputStream inputStream = file.getInputStream(); ExcelUtil salesLedgerImportDtoExcelUtil = new ExcelUtil<>(PurchaseLedgerImportDto.class); Map> stringListMap = salesLedgerImportDtoExcelUtil.importExcelMultiSheet(Arrays.asList("采购台账数据", "采购产品数据"), inputStream, 0); if (CollectionUtils.isEmpty(stringListMap)) return AjaxResult.error("采购表格为空!"); // 业务层合并 List salesLedgerImportDtoList = stringListMap.get("采购台账数据"); if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return AjaxResult.error("采购台账数据为空!"); List salesLedgerProductImportDtoList = stringListMap.get("采购产品数据"); if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return AjaxResult.error("采购产品数据为空!"); // 供应商数据 List customers = supplierManageMapper.selectList(new LambdaQueryWrapper().in(SupplierManage::getSupplierName, salesLedgerImportDtoList.stream().map(PurchaseLedgerImportDto::getSupplierName).collect(Collectors.toList()))); List> list = productModelMapper.getProductAndModelList(); // 录入人数据 List sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper().in(SysUser::getNickName, salesLedgerImportDtoList.stream().map(PurchaseLedgerImportDto::getRecorderName).collect(Collectors.toList()))); for (PurchaseLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper() .eq(PurchaseLedger::getPurchaseContractNumber, salesLedgerImportDto.getPurchaseContractNumber()) .last("limit 1")); if(purchaseLedger != null){ continue; } PurchaseLedger salesLedger = new PurchaseLedger(); BeanUtils.copyProperties(salesLedgerImportDto, salesLedger); // 通过供应商名称查询ID salesLedger.setSupplierId(customers.stream() .filter(customer -> customer.getSupplierName().equals(salesLedger.getSupplierName())) .findFirst() .map(SupplierManage::getId) .orElse(null)); Long aLong = sysUsers.stream() .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getRecorderName())) .findFirst() .map(SysUser::getUserId) .orElse(null); if (aLong == null) throw new RuntimeException("录入人:" + salesLedger.getRecorderName() + ",无对应用户!"); salesLedger.setRecorderId(aLong); // 采购产品数据绑定,通过采购单号获取对应采购产品数据 List salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream() .filter(salesLedgerProductImportDto -> salesLedgerProductImportDto.getPurchaseContractNumber().equals(salesLedger.getPurchaseContractNumber())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(salesLedgerProductImportDtos)) throw new RuntimeException("采购单号:" + salesLedgerImportDto.getPurchaseContractNumber() + ",无对应产品数据!"); salesLedger.setContractAmount(salesLedgerProductImportDtos.stream() .map(PurchaseLedgerProductImportDto::getTaxInclusiveTotalPrice) .reduce(BigDecimal.ZERO,BigDecimal::add)); // 通过销售单号绑定销售 SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper() .eq(SalesLedger::getSalesContractNo, salesLedger.getSalesContractNo()) .last("LIMIT 1")); if(salesLedger1 != null){ salesLedger.setSalesLedgerId(salesLedger1.getId()); } if (StringUtils.hasText(salesLedger.getApproveUserIds())) { // 采购审核:历史导入模板传审批人姓名时,继续兼容转换为用户ID。 String[] split = salesLedger.getApproveUserIds().split(","); List ids = new ArrayList<>(); for (int i = 0; i < split.length; i++) { SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper().eq(SysUser::getNickName, split[i]) .last("LIMIT 1")); if (sysUser != null) { ids.add(sysUser.getUserId()); } } // 将集合转为字符串,隔开 String collect = ids.stream().map(Object::toString).collect(Collectors.joining(",")); salesLedger.setApproveUserIds(collect); } purchaseLedgerMapper.insert(salesLedger); for (PurchaseLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct); salesLedgerProduct.setSalesLedgerId(salesLedger.getId()); salesLedgerProduct.setType(2); // 计算不含税总价 salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP)); list.stream() .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel())) .findFirst() .ifPresent(map -> { salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString())); salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString())); }); salesLedgerProduct.setRegister(loginUser.getNickName()); salesLedgerProduct.setRegisterDate(LocalDateTime.now()); salesLedgerProduct.setApproveStatus(0); // 是否质检判断 salesLedgerProduct.setIsChecked(salesLedgerProductImportDto.getIsChecked() == 1); if(salesLedgerProductImportDto.getIsChecked() == 1){ addQualityInspect(salesLedger, salesLedgerProduct); } salesLedgerProductMapper.insert(salesLedgerProduct); } // 采购审核 addApproveByPurchase(loginUser,salesLedger); } return AjaxResult.success("导入成功"); } catch (Exception e) { e.printStackTrace(); } return AjaxResult.success("导入失败"); } @Override public PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto) { // 1. 查询主表 PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper() .eq(PurchaseLedger::getPurchaseContractNumber, purchaseLedgerDto.getPurchaseContractNumber()) .last("LIMIT 1")); if (purchaseLedger == null) { throw new BaseException("采购台账不存在"); } // 2. 查询子表 LambdaQueryWrapper productWrapper = new LambdaQueryWrapper<>(); productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, 2); List products = salesLedgerProductMapper.selectList(productWrapper); // 4. 转换 DTO PurchaseLedgerDto resultDto = new PurchaseLedgerDto(); BeanUtils.copyProperties(purchaseLedger, resultDto); if (!products.isEmpty()) { resultDto.setHasChildren(true); resultDto.setProductData(products); } return resultDto; } public void addApproveByPurchase(LoginUser loginUser,PurchaseLedger purchaseLedger) throws Exception { if (loginUser == null) { return; } ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectOne( new LambdaQueryWrapper() .eq(ApprovalTemplate::getBusinessType, 5L) .orderByDesc(ApprovalTemplate::getId) .last("LIMIT 1") ); if (approvalTemplate == null) { throw new BaseException("请先配置采购审批模板"); } ApprovalInstanceDto approvalInstance = new ApprovalInstanceDto(); approvalInstance.setTemplateId(approvalTemplate.getId()); approvalInstance.setTemplateName(approvalTemplate.getTemplateName()); approvalInstance.setBusinessId(purchaseLedger.getId()); approvalInstance.setBusinessType(5L); approvalInstance.setCurrentLevel(1); approvalInstance.setApplicantId(loginUser.getUserId()); approvalInstance.setTitle(purchaseLedger.getPurchaseContractNumber()+"审批"); approvalInstance.setApplicantName(loginUser.getNickName()); approvalInstance.setApplyTime(LocalDateTime.now()); approvalInstanceService.add(approvalInstance); } /** * 下划线命名转驼峰命名 */ private String underlineToCamel(String param) { if (param == null || "".equals(param.trim())) { return ""; } int len = param.length(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { char c = param.charAt(i); if (c == '_') { if (++i < len) { sb.append(Character.toUpperCase(param.charAt(i))); } } else { sb.append(Character.toLowerCase(c)); } } return sb.toString(); } }