src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -95,6 +95,14 @@ } /** * 根据id查询采购合同号 */ @GetMapping("/getPurchaseNoById") public PurchaseLedgerDto getPurchaseNoById(Long id) { return purchaseLedgerService.getPurchaseNoById(id); } /** * 根据采购合同号查询产品 */ @GetMapping("/getProduct") src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -5,6 +5,7 @@ import com.ruoyi.sales.pojo.SalesLedgerProduct; import lombok.Data; import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -116,4 +117,21 @@ * 产品规格id */ private Long productModelId; /** * 发票号 */ private String invoiceNumber; /** * 发票金额(元) */ private BigDecimal invoiceAmount; /** * 来票登记id */ private Long ticketRegistrationId; } src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java
@@ -1,13 +1,20 @@ package com.ruoyi.purchase.dto; import com.baomidou.mybatisplus.annotation.TableName; import com.ruoyi.purchase.pojo.TicketRegistration; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.SalesLedgerProduct; import lombok.Data; import java.util.List; /** * 来票登记表 */ @Data public class TicketRegistrationDto { @TableName("ticket_registration") public class TicketRegistrationDto extends TicketRegistration { /** * 主键ID src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java
@@ -78,6 +78,12 @@ private BigDecimal invoiceAmount; /** * 开票人ID */ @Excel(name = "开票人") private String issUerId; /** * 开票人 */ @Excel(name = "开票人") src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -29,4 +29,6 @@ PurchaseLedgerDto getInfo(PurchaseLedgerDto purchaseLedgerDto); List getPurchasesNo(); PurchaseLedgerDto getPurchaseNoById(Long id); } src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -18,7 +18,9 @@ import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.purchase.dto.PurchaseLedgerDto; import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.mapper.TicketRegistrationMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.pojo.TicketRegistration; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.SalesLedgerMapper; @@ -73,6 +75,8 @@ private final ProductModelMapper productModelMapper; private final TicketRegistrationMapper ticketRegistrationMapper; @Value("${file.upload-dir}") private String uploadDir; @@ -118,7 +122,7 @@ // 4. 处理子表数据 List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData(); if (productList != null && !productList.isEmpty()) { handleSalesLedgerProducts(purchaseLedger.getId(), purchaseLedgerDto.getProductId(), purchaseLedgerDto.getProductModelId(), productList, purchaseLedgerDto.getType()); handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType()); } // 5. 迁移临时文件到正式目录 @@ -129,19 +133,52 @@ return 1; } private void handleSalesLedgerProducts(Long salesLedgerId, Long productId, Long productModelId, List<SalesLedgerProduct> products, Integer type) { Product pro = productMapper.selectById(productId); ProductModel productModel = productModelMapper.selectById(productModelId); private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) { if (products == null || products.isEmpty()) { throw new BaseException("产品信息不存在"); } // 按ID分组,区分新增和更新的记录 // 提前收集所有需要查询的ID Set<Long> productIds = products.stream() .map(SalesLedgerProduct::getProductId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Set<Long> modelIds = products.stream() .map(SalesLedgerProduct::getProductModelId) .filter(Objects::nonNull) .collect(Collectors.toSet()); // 一次性查询产品和型号信息 Map<Long, String> productMap = new HashMap<>(); if (!productIds.isEmpty()) { List<Product> productList = productMapper.selectBatchIds(productIds); productList.forEach(p -> productMap.put(p.getId(), p.getProductName())); } Map<Long, String> modelMap = new HashMap<>(); if (!modelIds.isEmpty()) { List<ProductModel> 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<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream() .peek(p -> { p.setSalesLedgerId(salesLedgerId); p.setProductId(productId); p.setProductCategory(pro.getProductName()); p.setProductModelId(productModelId); p.setSpecificationModel(productModel.getModel()); }) .collect(Collectors.partitioningBy(p -> p.getId() != null)); List<SalesLedgerProduct> updateList = partitionedProducts.get(true); @@ -315,6 +352,10 @@ queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, 2); List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper); productList.forEach(product -> { product.setFutureTickets(product.getFutureTickets() != null ? product.getFutureTickets() : product.getQuantity().longValue()); product.setFutureTicketsAmount(product.getFutureTicketsAmount() != null ? product.getFutureTicketsAmount() : product.getTaxInclusiveTotalPrice()); }); resultDto.setProductData(productList); return resultDto; @@ -336,6 +377,20 @@ ).collect(Collectors.toList()); } @Override public PurchaseLedgerDto getPurchaseNoById(Long id) { PurchaseLedgerDto purchaseLedgerDto = new PurchaseLedgerDto(); PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); BeanUtils.copyProperties(purchaseLedger,purchaseLedgerDto); TicketRegistration ticketRegistration = ticketRegistrationMapper.selectOne(new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getPurchaseLedgerId, id)); if (ticketRegistration != null) { purchaseLedgerDto.setInvoiceNumber(ticketRegistration.getInvoiceNumber()); purchaseLedgerDto.setInvoiceAmount(ticketRegistration.getInvoiceAmount()); purchaseLedgerDto.setTicketRegistrationId(ticketRegistration.getId()); } return purchaseLedgerDto; } /** * 下划线命名转驼峰命名 */ src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java
@@ -74,31 +74,45 @@ @Override public int addOrUpdateRegistration(TicketRegistrationDto ticketRegistrationDto) throws IOException { // 1. 查询采购台账记录 PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(ticketRegistrationDto.getPurchaseLedgerId()); if (purchaseLedger == null) { // 处理采购台账不存在的情况,例如抛出异常或返回错误 throw new IllegalArgumentException("采购台账记录不存在,ID: " + ticketRegistrationDto.getPurchaseLedgerId()); } // 2. 查询是否已存在票据登记记录 TicketRegistration existingRecord = ticketRegistrationMapper.selectOne( new LambdaQueryWrapper<TicketRegistration>() .eq(TicketRegistration::getPurchaseLedgerId, ticketRegistrationDto.getPurchaseLedgerId()) ); // 3. 创建或更新票据登记实体 TicketRegistration ticketRegistration = new TicketRegistration(); BeanUtils.copyProperties(ticketRegistrationDto, ticketRegistration); if (existingRecord != null){ ticketRegistration.setId(existingRecord.getId()); } ticketRegistration.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber()); ticketRegistration.setTenantId(purchaseLedger.getTenantId()); ticketRegistration.setContractAmount(purchaseLedger.getContractAmount()); // 处理子表数据 // 4. 处理子表数据 List<SalesLedgerProduct> productData = ticketRegistrationDto.getProductData(); if (productData != null && !productData.isEmpty()) { if (CollectionUtils.isNotEmpty(productData)) { handleSalesLedgerProducts(purchaseLedger.getId(), productData, 2); } // 执行插入或更新操作 int i; if (ticketRegistrationDto.getId() == null) { i = ticketRegistrationMapper.insert(ticketRegistration); } else { i = ticketRegistrationMapper.updateById(ticketRegistration); } // 5. 执行插入或更新操作 int rowsAffected = existingRecord != null ? ticketRegistrationMapper.updateById(ticketRegistration) : ticketRegistrationMapper.insert(ticketRegistration); // 迁移临时文件到正式目录 if (ticketRegistrationDto.getTempFileIds() != null && !ticketRegistrationDto.getTempFileIds().isEmpty()) { migrateTempFilesToFormal(ticketRegistration.getId(), ticketRegistrationDto.getTempFileIds()); } return i; return rowsAffected; } @@ -216,8 +230,32 @@ // 批量更新(需要 MyBatis 提供批量更新方法) if (!updateList.isEmpty()) { updateList.forEach(product -> { product.setFutureTickets(product.getQuantity().subtract(new BigDecimal(product.getTicketsNum())).longValue()); product.setFutureTicketsAmount(product.getTaxExclusiveTotalPrice().subtract(product.getTicketsAmount())); // 非空校验,任一字段为空则抛出异常 if (product.getQuantity() == null) { throw new BaseException("数量不能为空"); } if (product.getTicketsNum() == null) { throw new BaseException("已开票数量不能为空"); } if (product.getTaxExclusiveTotalPrice() == null) { throw new BaseException("不含税总价不能为空"); } if (product.getTicketsAmount() == null) { throw new BaseException("本次来票金额(元)不能为空"); } // 计算 futureTickets(直接使用 BigDecimal 计算,避免精度丢失) product.setFutureTickets( product.getQuantity() .subtract(BigDecimal.valueOf(product.getTicketsNum())) .longValueExact() // 使用 exact 方法确保无小数部分 ); // 计算 futureTicketsAmount product.setFutureTicketsAmount( product.getTaxExclusiveTotalPrice() .subtract(product.getTicketsAmount()) ); product.setType(type); salesLedgerProductMapper.updateById(product); });