package com.ruoyi.purchase.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 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.vo.ApproveProcessVO; import com.ruoyi.approve.pojo.ApproveProcess; 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.enums.FileNameType; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.AmountUtils; 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.other.mapper.TempFileMapper; import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper; import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; 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.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.impl.CommonFileServiceImpl; 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.time.Instant; 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 static final Long IMPORT_PRODUCT_PARENT_ID = 3L; 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 SysDeptMapper sysDeptMapper; 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; @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); AmountUtils.normalizeContractAmount(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; } 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 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) { AmountUtils.normalizeSalesLedgerProduct(product); 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 = AmountUtils.scaleAmount(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); AmountUtils.normalizeContractAmount(resultDto); if (!products.isEmpty()) { AmountUtils.normalizeSalesLedgerProducts(products); 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); AmountUtils.normalizeSalesLedgerProducts(productList); 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) { IPage page = purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger); if (!CollectionUtils.isEmpty(page.getRecords())) { page.getRecords().forEach(record -> { AmountUtils.normalizeContractAmount(record); AmountUtils.normalizeSalesLedgerProducts(record.getProductData()); }); } return page; } @Override public String getPurchaseNo() { // 生成日期前缀(例如:CG20250405) String purchaseNo = "CG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 构建 Redis Key(按天分隔) String redisKey = "purchase_no:" + LocalDate.now().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 excelUtil = new ExcelUtil<>(PurchaseLedgerImportDto.class); Map> sheetData = excelUtil.importExcelMultiSheet( Arrays.asList("采购台账数据", "采购产品数据"), inputStream, 0); if (CollectionUtils.isEmpty(sheetData)) { return AjaxResult.error("采购表格为空!"); } List purchaseImports = sheetData.get("采购台账数据"); if (CollectionUtils.isEmpty(purchaseImports)) { return AjaxResult.error("采购台账数据为空!"); } List productImports = sheetData.get("采购产品数据"); if (CollectionUtils.isEmpty(productImports)) { return AjaxResult.error("采购产品数据为空!"); } List supplierNames = purchaseImports.stream() .map(PurchaseLedgerImportDto::getSupplierName) .filter(StringUtils::hasText) .map(StringUtils::trim) .distinct() .collect(Collectors.toList()); Map supplierMap = CollectionUtils.isEmpty(supplierNames) ? Collections.emptyMap() : supplierManageMapper.selectList(new LambdaQueryWrapper() .in(SupplierManage::getSupplierName, supplierNames)) .stream() .collect(Collectors.toMap( supplier -> StringUtils.trim(supplier.getSupplierName()), supplier -> supplier, (first, ignored) -> first)); List recorderNames = purchaseImports.stream() .map(PurchaseLedgerImportDto::getRecorderName) .filter(StringUtils::hasText) .map(StringUtils::trim) .distinct() .collect(Collectors.toList()); Map recorderMap = CollectionUtils.isEmpty(recorderNames) ? Collections.emptyMap() : sysUserMapper.selectList(new LambdaQueryWrapper() .in(SysUser::getNickName, recorderNames)) .stream() .collect(Collectors.toMap( user -> StringUtils.trim(user.getNickName()), user -> user, (first, ignored) -> first)); Map importedProductModelCache = new HashMap<>(); int addedCount = 0; int overwrittenCount = 0; int skippedCount = 0; for (PurchaseLedgerImportDto purchaseImport : purchaseImports) { String purchaseContractNumber = requireImportText( purchaseImport.getPurchaseContractNumber(), "采购单号不能为空!"); purchaseImport.setPurchaseContractNumber(purchaseContractNumber); purchaseImport.setSupplierName(StringUtils.trim(purchaseImport.getSupplierName())); purchaseImport.setProjectName(StringUtils.trim(purchaseImport.getProjectName())); purchaseImport.setRecorderName(StringUtils.trim(purchaseImport.getRecorderName())); List purchaseProducts = productImports.stream() .filter(productImport -> sameImportText( productImport.getPurchaseContractNumber(), purchaseContractNumber)) .map(productImport -> (PurchaseLedgerProductImportDto) productImport) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(purchaseProducts)) { throw new BaseException("采购单号:" + purchaseContractNumber + ",无对应产品数据!"); } List existingLedgers = purchaseLedgerMapper.selectList( new LambdaQueryWrapper() .eq(PurchaseLedger::getPurchaseContractNumber, purchaseContractNumber)); PurchaseLedger ledgerToOverwrite = existingLedgers.stream() .filter(existing -> Objects.equals(existing.getApprovalStatus(), 1)) .filter(existing -> isSameImportedPurchase(existing, purchaseImport)) .findFirst() .orElse(null); if (ledgerToOverwrite == null && CollectionUtils.isNotEmpty(existingLedgers)) { skippedCount++; continue; } PurchaseLedger purchaseLedger = buildImportedPurchaseLedger( purchaseImport, purchaseProducts, supplierMap, recorderMap); boolean overwrite = ledgerToOverwrite != null; if (overwrite) { purchaseLedger.setId(ledgerToOverwrite.getId()); purchaseLedger.setApprovalStatus(1); updateImportedPurchaseLedger(purchaseLedger); clearImportedPurchaseContents(purchaseLedger.getId(), purchaseContractNumber); overwrittenCount++; } else { purchaseLedger.setApprovalStatus(1); purchaseLedgerMapper.insert(purchaseLedger); addedCount++; } for (PurchaseLedgerProductImportDto productImport : purchaseProducts) { ProductModel productModel = findOrCreateImportedProductModel( productImport, importedProductModelCache); SalesLedgerProduct purchaseProduct = new SalesLedgerProduct(); BeanUtils.copyProperties(productImport, purchaseProduct); purchaseProduct.setSalesLedgerId(purchaseLedger.getId()); purchaseProduct.setType(2); purchaseProduct.setProductId(productModel.getProductId()); purchaseProduct.setProductModelId(productModel.getId()); AmountUtils.normalizeSalesLedgerProduct(purchaseProduct); purchaseProduct.setTaxExclusiveTotalPrice( AmountUtils.calcTaxExclusiveTotalPrice( purchaseProduct.getTaxInclusiveTotalPrice(), purchaseProduct.getTaxRate())); purchaseProduct.setRegister(loginUser.getNickName()); purchaseProduct.setRegisterDate(LocalDateTime.now()); purchaseProduct.setApproveStatus(0); purchaseProduct.setIsChecked(Objects.equals(productImport.getIsChecked(), 1)); salesLedgerProductMapper.insert(purchaseProduct); if (Boolean.TRUE.equals(purchaseProduct.getIsChecked())) { addQualityInspect(purchaseLedger, purchaseProduct); } } if (!overwrite) { addApproveByPurchase(loginUser, purchaseLedger); } } return AjaxResult.success(String.format( "导入成功:新增%d条,覆盖%d条,跳过%d条", addedCount, overwrittenCount, skippedCount)); } catch (BaseException e) { log.error("导入采购台账失败:{}", e.getMessage(), e); throw e; } catch (Exception e) { log.error("导入采购台账失败", e); throw new BaseException("导入失败:" + e.getMessage()); } } private PurchaseLedger buildImportedPurchaseLedger( PurchaseLedgerImportDto purchaseImport, List purchaseProducts, Map supplierMap, Map recorderMap) { PurchaseLedger purchaseLedger = new PurchaseLedger(); BeanUtils.copyProperties(purchaseImport, purchaseLedger); SupplierManage supplier = supplierMap.get(purchaseLedger.getSupplierName()); purchaseLedger.setSupplierId(supplier == null ? null : supplier.getId()); SysUser recorder = recorderMap.get(purchaseLedger.getRecorderName()); if (recorder == null) { throw new BaseException("录入人:" + purchaseLedger.getRecorderName() + ",无对应用户!"); } purchaseLedger.setRecorderId(recorder.getUserId()); purchaseLedger.setContractAmount(purchaseProducts.stream() .map(PurchaseLedgerProductImportDto::getTaxInclusiveTotalPrice) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add)); if (StringUtils.hasText(purchaseLedger.getSalesContractNo())) { SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper() .eq(SalesLedger::getSalesContractNo, purchaseLedger.getSalesContractNo()) .last("LIMIT 1")); purchaseLedger.setSalesLedgerId(salesLedger == null ? null : salesLedger.getId()); } else { purchaseLedger.setSalesLedgerId(null); } purchaseLedger.setApproveUserIds(convertImportedApproverNames(purchaseLedger.getApproveUserIds())); return purchaseLedger; } private String convertImportedApproverNames(String approverNames) { if (!StringUtils.hasText(approverNames)) { return approverNames; } List userIds = new ArrayList<>(); for (String approverName : approverNames.split("[,,]")) { String trimmedName = StringUtils.trim(approverName); if (!StringUtils.hasText(trimmedName)) { continue; } SysUser user = sysUserMapper.selectOne(new LambdaQueryWrapper() .eq(SysUser::getNickName, trimmedName) .last("LIMIT 1")); if (user != null) { userIds.add(user.getUserId()); } } return userIds.stream().map(String::valueOf).collect(Collectors.joining(",")); } private ProductModel findOrCreateImportedProductModel( PurchaseLedgerProductImportDto productImport, Map cache) { String productCategory = requireImportText( productImport.getProductCategory(), "采购产品的产品大类不能为空!"); String specificationModel = StringUtils.trim(productImport.getSpecificationModel()); if (!StringUtils.hasText(specificationModel)) { specificationModel = productCategory; } productImport.setProductCategory(productCategory); productImport.setSpecificationModel(specificationModel); productImport.setUnit(StringUtils.trim(productImport.getUnit())); String cacheKey = productCategory + "::" + specificationModel; ProductModel cachedModel = cache.get(cacheKey); if (cachedModel != null) { return cachedModel; } List sameNameProducts = productMapper.selectList(new LambdaQueryWrapper() .eq(Product::getProductName, productCategory)); for (Product product : sameNameProducts) { ProductModel existingModel = productModelMapper.selectOne(new LambdaQueryWrapper() .eq(ProductModel::getProductId, product.getId()) .eq(ProductModel::getModel, specificationModel) .last("LIMIT 1")); if (existingModel != null) { cache.put(cacheKey, existingModel); return existingModel; } } Product product = sameNameProducts.stream() .filter(item -> Objects.equals(item.getParentId(), IMPORT_PRODUCT_PARENT_ID)) .findFirst() .orElse(null); if (product == null) { product = new Product(); product.setParentId(IMPORT_PRODUCT_PARENT_ID); product.setProductName(productCategory); productMapper.insert(product); } ProductModel productModel = new ProductModel(); productModel.setProductId(product.getId()); productModel.setModel(specificationModel); productModel.setUnit(productImport.getUnit()); productModel.setProductCode(specificationModel + "-001"); productModelMapper.insert(productModel); cache.put(cacheKey, productModel); return productModel; } private void updateImportedPurchaseLedger(PurchaseLedger purchaseLedger) { purchaseLedgerMapper.update(null, new LambdaUpdateWrapper() .eq(PurchaseLedger::getId, purchaseLedger.getId()) .set(PurchaseLedger::getPurchaseContractNumber, purchaseLedger.getPurchaseContractNumber()) .set(PurchaseLedger::getSupplierId, purchaseLedger.getSupplierId()) .set(PurchaseLedger::getSupplierName, purchaseLedger.getSupplierName()) .set(PurchaseLedger::getRecorderId, purchaseLedger.getRecorderId()) .set(PurchaseLedger::getRecorderName, purchaseLedger.getRecorderName()) .set(PurchaseLedger::getSalesContractNo, purchaseLedger.getSalesContractNo()) .set(PurchaseLedger::getProjectName, purchaseLedger.getProjectName()) .set(PurchaseLedger::getEntryDate, purchaseLedger.getEntryDate()) .set(PurchaseLedger::getExecutionDate, purchaseLedger.getExecutionDate()) .set(PurchaseLedger::getRemarks, purchaseLedger.getRemarks()) .set(PurchaseLedger::getSalesLedgerId, purchaseLedger.getSalesLedgerId()) .set(PurchaseLedger::getContractAmount, purchaseLedger.getContractAmount()) .set(PurchaseLedger::getPaymentMethod, purchaseLedger.getPaymentMethod()) .set(PurchaseLedger::getApproveUserIds, purchaseLedger.getApproveUserIds()) .set(PurchaseLedger::getApprovalStatus, 1) .set(PurchaseLedger::getUpdatedAt, new Date())); } private void clearImportedPurchaseContents(Long purchaseLedgerId, String purchaseContractNumber) { List qualityInspects = qualityInspectMapper.selectList( new LambdaQueryWrapper() .eq(QualityInspect::getPurchaseLedgerId, purchaseLedgerId)); boolean hasSubmittedInspect = qualityInspects.stream() .anyMatch(inspect -> Objects.equals(inspect.getInspectState(), 1)); if (hasSubmittedInspect) { throw new BaseException("采购单号:" + purchaseContractNumber + ",存在已提交的检验单,不能覆盖!"); } List inspectIds = qualityInspects.stream() .map(QualityInspect::getId) .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(inspectIds)) { qualityInspectParamMapper.delete(new LambdaQueryWrapper() .in(QualityInspectParam::getInspectId, inspectIds)); qualityInspectMapper.delete(new LambdaQueryWrapper() .eq(QualityInspect::getPurchaseLedgerId, purchaseLedgerId)); } List existingProducts = salesLedgerProductMapper.selectList( new LambdaQueryWrapper() .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedgerId) .eq(SalesLedgerProduct::getType, 2)); for (SalesLedgerProduct existingProduct : existingProducts) { procurementRecordStorageMapper.delete(new LambdaQueryWrapper() .eq(ProcurementRecordStorage::getSalesLedgerProductId, existingProduct.getId())); } salesLedgerProductMapper.delete(new LambdaQueryWrapper() .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedgerId) .eq(SalesLedgerProduct::getType, 2)); } private boolean isSameImportedPurchase( PurchaseLedger existingLedger, PurchaseLedgerImportDto purchaseImport) { return sameImportText(existingLedger.getPurchaseContractNumber(), purchaseImport.getPurchaseContractNumber()) && sameImportText(existingLedger.getSupplierName(), purchaseImport.getSupplierName()) && sameImportText(existingLedger.getProjectName(), purchaseImport.getProjectName()) && sameImportDate(existingLedger.getExecutionDate(), purchaseImport.getExecutionDate()) && sameImportDate(existingLedger.getEntryDate(), purchaseImport.getEntryDate()); } private boolean sameImportText(String left, String right) { return Objects.equals(StringUtils.trim(left), StringUtils.trim(right)); } private boolean sameImportDate(Date left, Date right) { if (left == null || right == null) { return left == null && right == null; } LocalDate leftDate = Instant.ofEpochMilli(left.getTime()) .atZone(ZoneId.systemDefault()) .toLocalDate(); LocalDate rightDate = Instant.ofEpochMilli(right.getTime()) .atZone(ZoneId.systemDefault()) .toLocalDate(); return leftDate.equals(rightDate); } private String requireImportText(String value, String message) { String trimmedValue = StringUtils.trim(value); if (!StringUtils.hasText(trimmedValue)) { throw new BaseException(message); } return trimmedValue; } @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); AmountUtils.normalizeContractAmount(resultDto); if (!products.isEmpty()) { AmountUtils.normalizeSalesLedgerProducts(products); resultDto.setHasChildren(true); resultDto.setProductData(products); } return resultDto; } public void addApproveByPurchase(LoginUser loginUser,PurchaseLedger purchaseLedger) throws Exception { if (loginUser == null) { return; } ApproveProcessVO approveProcessVO = new ApproveProcessVO(); approveProcessVO.setApproveType(5); approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId()); approveProcessVO.setApproveReason(purchaseLedger.getPurchaseContractNumber()); approveProcessVO.setApproveUserIds(purchaseLedger.getApproveUserIds()); approveProcessVO.setApproveUser(loginUser.getUserId()); approveProcessVO.setApproveTime(LocalDate.now().toString()); approveProcessVO.setPrice(AmountUtils.scaleAmount(purchaseLedger.getContractAmount())); approveProcessService.addApprove(approveProcessVO); } /** * 下划线命名转驼峰命名 */ 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(); } @Override public Map getPrintData(Long id) { PurchaseLedger purchaseLedger = getById(id); if (purchaseLedger == null) { return null; } List products = salesLedgerProductMapper.selectList( new LambdaQueryWrapper() .eq(SalesLedgerProduct::getSalesLedgerId, id) .eq(SalesLedgerProduct::getType, 2) ); SysDept dept = sysDeptMapper.selectDeptById(100L); Map result = new HashMap<>(); result.put("companyName", dept != null ? dept.getDeptName() : ""); result.put("ledger", purchaseLedger); result.put("products", products); return result; } }