| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.lang.reflect.Field; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.net.URLEncoder; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockOutRecordService stockOutRecordService; |
| | | private final StockUtils stockUtils; |
| | | private final ShipmentApprovalMapper shipmentApprovalMapper; |
| | | |
| | | @Autowired |
| | | private IApproveProcessService approveProcessService; |
| | | |
| | |
| | | if (CollectionUtils.isEmpty(idList)) { |
| | | return 0; |
| | | } |
| | | // 校验:已审核的订单不能删除 |
| | | List<SalesLedger> ledgers = salesLedgerMapper.selectBatchIds(idList); |
| | | for (SalesLedger ledger : ledgers) { |
| | | if (ledger.getReviewStatus() != null && ledger.getReviewStatus() == 1) { |
| | | throw new ServiceException("已审核的订单不能删除:" + ledger.getSalesContractNo()); |
| | | } |
| | | } |
| | | // 删除销售管理数据 |
| | | LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList).select(SalesLedgerProduct::getId); |
| | |
| | | if (salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("订单已发货,禁止编辑"); |
| | | } |
| | | // 查询数据库中的原始记录用于校验 |
| | | SalesLedger existingLedger = salesLedgerMapper.selectById(salesLedger.getId()); |
| | | if (salesLedger.getReviewStatus() != null && salesLedger.getReviewStatus() == 1) { |
| | | // 审核操作:校验审核人不能是录入人(仅对未审核→已审核的转换) |
| | | if (existingLedger != null && existingLedger.getReviewStatus() != null && existingLedger.getReviewStatus() == 0) { |
| | | Long currentUserId = SecurityUtils.getUserId(); |
| | | String entryPerson = existingLedger.getEntryPerson(); |
| | | if (entryPerson != null && entryPerson.equals(String.valueOf(currentUserId))) { |
| | | throw new ServiceException("不能审核本人录入的订单"); |
| | | } |
| | | } |
| | | salesLedger.setReviewStatus(salesLedgerDto.getReviewStatus()); |
| | | } else if (salesLedger.getReviewStatus() != null && salesLedger.getReviewStatus() == 2) { |
| | | handleCounterReview(salesLedger); |
| | | } else { |
| | | // 未审核状态的编辑操作:校验已审核的订单不能编辑 |
| | | if (existingLedger != null && existingLedger.getReviewStatus() != null && existingLedger.getReviewStatus() == 1) { |
| | | throw new ServiceException("已审核的订单不能编辑"); |
| | | } |
| | | salesLedger.setReviewStatus(0); |
| | | } |
| | | salesLedgerMapper.updateById(salesLedger); |
| | |
| | | * 2. 复制原销售台账及产品数据,生成新的台账 |
| | | * 3. 对原台账的库存数据进行反向操作 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public List<Long> counterReview(CounterReviewDto dto) { |
| | | if (dto == null || CollectionUtils.isEmpty(dto.getIds())) { |
| | | throw new ServiceException("请选择要反审核的订单"); |
| | | } |
| | | if (dto.getCounterReviewType() == null || (dto.getCounterReviewType() != 1 && dto.getCounterReviewType() != 2)) { |
| | | throw new ServiceException("请选择反审核类型:作废或重新生成"); |
| | | } |
| | | if (dto.getCounterReviewDesc() == null || dto.getCounterReviewDesc().trim().isEmpty()) { |
| | | throw new ServiceException("请输入反审核描述"); |
| | | } |
| | | |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | List<Long> newLedgerIds = new ArrayList<>(); |
| | | |
| | | for (Long id : dto.getIds()) { |
| | | SalesLedger originalLedger = salesLedgerMapper.selectById(id); |
| | | if (originalLedger == null) { |
| | | throw new ServiceException("订单不存在,无法反审核"); |
| | | } |
| | | if (originalLedger.getReviewStatus() == null || originalLedger.getReviewStatus() != 1) { |
| | | throw new ServiceException("订单" + originalLedger.getSalesContractNo() + "不是已审核状态,无法反审核"); |
| | | } |
| | | |
| | | // 1. 标记原订单为已反审 |
| | | originalLedger.setReviewStatus(2); |
| | | originalLedger.setCounterReviewTime(LocalDateTime.now()); |
| | | originalLedger.setCounterReviewPerson(loginUser.getUser().getNickName()); |
| | | originalLedger.setCounterReviewPersonId(loginUser.getUserId()); |
| | | originalLedger.setCounterReviewType(dto.getCounterReviewType()); |
| | | originalLedger.setCounterReviewDesc(dto.getCounterReviewDesc()); |
| | | salesLedgerMapper.updateById(originalLedger); |
| | | |
| | | // 2. 作废库存:入库扣减、出库增加、删除记录 |
| | | processOriginalOrderStock(id); |
| | | |
| | | // 3. 清除质检记录 |
| | | clearQualityInspectRecords(id); |
| | | |
| | | // 4. 清除发货信息和发货审批记录 |
| | | clearShippingAndApprovalRecords(id); |
| | | |
| | | // 5. 取消审批流程 |
| | | cancelApproveProcesses(id, originalLedger.getSalesContractNo()); |
| | | |
| | | // 6. 重新生成:创建新台账副本 |
| | | if (dto.getCounterReviewType() == 2) { |
| | | SalesLedger newLedger = new SalesLedger(); |
| | | BeanUtils.copyProperties(originalLedger, newLedger); |
| | | newLedger.setId(null); |
| | | newLedger.setSalesContractNo(generateSalesContractNo()); |
| | | newLedger.setDeliveryStatus(1); |
| | | newLedger.setStockStatus(0); |
| | | newLedger.setReviewStatus(0); |
| | | newLedger.setCounterReviewTime(null); |
| | | newLedger.setCounterReviewPerson(null); |
| | | newLedger.setCounterReviewPersonId(null); |
| | | newLedger.setCounterReviewType(null); |
| | | newLedger.setCounterReviewDesc(null); |
| | | salesLedgerMapper.insert(newLedger); |
| | | |
| | | // 复制产品到新台账 |
| | | List<SalesLedgerProduct> originalProducts = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, id) |
| | | ); |
| | | for (SalesLedgerProduct originalProduct : originalProducts) { |
| | | SalesLedgerProduct newProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(originalProduct, newProduct); |
| | | newProduct.setId(null); |
| | | newProduct.setSalesLedgerId(newLedger.getId()); |
| | | newProduct.setStockedQuantity(BigDecimal.ZERO); |
| | | newProduct.setShippedQuantity(BigDecimal.ZERO); |
| | | newProduct.setUnqualifiedStockedQuantity(BigDecimal.ZERO); |
| | | newProduct.setUnqualifiedShippedQuantity(BigDecimal.ZERO); |
| | | newProduct.setReturnQuality(BigDecimal.ZERO); |
| | | newProduct.setAvailableQuality(newProduct.getQuantity().subtract(newProduct.getReturnQuality())); |
| | | newProduct.setProductStockStatus(0); |
| | | newProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.insert(newProduct); |
| | | } |
| | | newLedgerIds.add(newLedger.getId()); |
| | | } |
| | | } |
| | | return newLedgerIds; |
| | | } |
| | | |
| | | /** |
| | | * 旧版反审处理(兼容 addOrUpdateSalesLedger 中 reviewStatus=2 的调用) |
| | | */ |
| | | private void handleCounterReview(SalesLedger salesLedger) { |
| | | // 1. 设置反审相关信息 |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | |
| | | |
| | | // 6. 处理原订单的库存数据(生成反审出入库记录) |
| | | processOriginalOrderStock(originalSalesLedgerId); |
| | | |
| | | // 7. 清除原订单的质检记录 |
| | | clearQualityInspectRecords(originalSalesLedgerId); |
| | | |
| | | // 8. 清除原订单的发货信息和发货审批记录 |
| | | clearShippingAndApprovalRecords(originalSalesLedgerId); |
| | | |
| | | // 9. 取消原订单相关的审批流程 |
| | | cancelApproveProcesses(originalSalesLedgerId, originalLedger.getSalesContractNo()); |
| | | } |
| | | |
| | | /** |
| | | * 清除原订单的质检记录 |
| | | */ |
| | | private void clearQualityInspectRecords(Long originalSalesLedgerId) { |
| | | // 删除与原订单关联的质检记录 |
| | | qualityInspectMapper.delete( |
| | | Wrappers.<QualityInspect>lambdaQuery() |
| | | .eq(QualityInspect::getPurchaseLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 清除原订单的发货信息和发货审批记录 |
| | | */ |
| | | private void clearShippingAndApprovalRecords(Long originalSalesLedgerId) { |
| | | // 1. 查询原订单的所有发货信息 |
| | | List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList( |
| | | Wrappers.<ShippingInfo>lambdaQuery() |
| | | .eq(ShippingInfo::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 2. 删除发货审批记录 |
| | | if (!CollectionUtils.isEmpty(shippingInfos)) { |
| | | List<Long> shippingInfoIds = shippingInfos.stream() |
| | | .map(ShippingInfo::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | shipmentApprovalMapper.delete( |
| | | Wrappers.<ShipmentApproval>lambdaQuery() |
| | | .eq(ShipmentApproval::getSalesLedgerId, originalSalesLedgerId) |
| | | .or() |
| | | .in(ShipmentApproval::getShippingInfoId, shippingInfoIds) |
| | | ); |
| | | |
| | | // 3. 删除发货信息记录 |
| | | shippingInfoMapper.delete( |
| | | Wrappers.<ShippingInfo>lambdaQuery() |
| | | .eq(ShippingInfo::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 取消原订单相关的审批流程 |
| | | */ |
| | | private void cancelApproveProcesses(Long originalSalesLedgerId, String originalSalesContractNo) { |
| | | // 取消入库审批流程 |
| | | List<ApproveProcess> stockInApproveProcesses = approveProcessService.list( |
| | | new LambdaQueryWrapper<ApproveProcess>() |
| | | .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()) |
| | | .like(ApproveProcess::getApproveRemark, "salesStock:" + originalSalesLedgerId + ":") |
| | | .eq(ApproveProcess::getApproveDelete, 0) |
| | | ); |
| | | |
| | | for (ApproveProcess process : stockInApproveProcesses) { |
| | | process.setApproveStatus(3); // 设置为审批失败状态 |
| | | process.setApproveDelete(1); // 标记为已删除 |
| | | approveProcessService.updateById(process); |
| | | } |
| | | |
| | | // 取消发货审批流程 |
| | | List<ApproveProcess> deliveryApproveProcesses = approveProcessService.list( |
| | | new LambdaQueryWrapper<ApproveProcess>() |
| | | .eq(ApproveProcess::getApproveType, 7) // 发货审批类型 |
| | | .like(ApproveProcess::getApproveReason, "发货审批:" + originalSalesContractNo) |
| | | .eq(ApproveProcess::getApproveDelete, 0) |
| | | ); |
| | | |
| | | for (ApproveProcess process : deliveryApproveProcesses) { |
| | | process.setApproveStatus(3); // 设置为审批失败状态 |
| | | process.setApproveDelete(1); // 标记为已删除 |
| | | approveProcessService.updateById(process); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理原订单的库存数据 |
| | | * 1. 对原订单的入库数据生成反审出库记录(销售-反审出库) |
| | | * 2. 对原订单的出库数据生成反审入库记录(销售-反审入库) |
| | | * 3. 更新库存表数据 |
| | | * 1. 删除原订单的所有入库记录,并扣减库存 |
| | | * 2. 删除原订单的所有出库记录,并增加库存 |
| | | */ |
| | | private void processOriginalOrderStock(Long originalSalesLedgerId) { |
| | | // 1. 查询原订单的所有入库记录 |
| | |
| | | .eq(StockInRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 2. 对每条入库记录生成对应的反审出库记录 |
| | | // 2. 删除入库记录并扣减库存 |
| | | for (StockInRecord stockInRecord : stockInRecords) { |
| | | // 2.1 创建反审出库记录 |
| | | StockOutRecord stockOutRecord = new StockOutRecord(); |
| | | stockOutRecord.setOutboundBatches(OrderUtils.countTodayByCreateTime(stockOutRecordMapper, "CK")); // 生成出库批次号 |
| | | stockOutRecord.setStockOutNum(stockInRecord.getStockInNum()); // 出库数量等于原入库数量 |
| | | stockOutRecord.setRecordId(stockInRecord.getId()); // 记录原入库记录ID |
| | | stockOutRecord.setRecordType(StockOutQualifiedRecordTypeEnum.SALE_COUNTER_REVIEW_STOCK_OUT.getCode()); // 设置为销售反审出库类型 |
| | | stockOutRecord.setProductModelId(stockInRecord.getProductModelId()); // 产品规格ID |
| | | stockOutRecord.setRemark("销售-反审出库"); // 备注 |
| | | stockOutRecord.setType(stockInRecord.getType()); // 类型(合格/不合格) |
| | | stockOutRecord.setSalesLedgerId(stockInRecord.getSalesLedgerId()); // 销售订单ID |
| | | stockOutRecord.setSalesLedgerProductId(stockInRecord.getSalesLedgerProductId()); // 销售订单产品ID |
| | | |
| | | // 2.2 插入反审出库记录 |
| | | stockOutRecordMapper.insert(stockOutRecord); |
| | | |
| | | // 2.3 从库存表中扣减相应数量 |
| | | // 从库存表中扣减相应数量 |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setProductModelId(stockOutRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockOutRecord.getStockOutNum()); |
| | | stockInventoryDto.setProductModelId(stockInRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockInRecord.getStockInNum()); |
| | | stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); |
| | | } |
| | | |
| | | // 3. 查询原订单的所有出库记录 |
| | | // 3. 删除所有入库记录 |
| | | stockInRecordMapper.delete( |
| | | Wrappers.<StockInRecord>lambdaQuery() |
| | | .eq(StockInRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 4. 查询原订单的所有出库记录 |
| | | List<StockOutRecord> stockOutRecords = stockOutRecordMapper.selectList( |
| | | Wrappers.<StockOutRecord>lambdaQuery() |
| | | .eq(StockOutRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 4. 对每条出库记录生成对应的反审入库记录 |
| | | // 5. 删除出库记录并增加库存 |
| | | for (StockOutRecord stockOutRecord : stockOutRecords) { |
| | | // 4.1 创建反审入库记录 |
| | | StockInRecord stockInRecord = new StockInRecord(); |
| | | stockInRecord.setInboundBatches(OrderUtils.countTodayByCreateTime(stockInRecordMapper, "RK")); // 生成入库批次号 |
| | | stockInRecord.setStockInNum(stockOutRecord.getStockOutNum()); // 入库数量等于原出库数量 |
| | | stockInRecord.setRecordId(stockOutRecord.getId()); // 记录原出库记录ID |
| | | stockInRecord.setRecordType(StockInQualifiedRecordTypeEnum.SALE_COUNTER_REVIEW_STOCK_IN.getCode()); // 设置为销售反审入库类型 |
| | | stockInRecord.setProductModelId(stockOutRecord.getProductModelId()); // 产品规格ID |
| | | stockInRecord.setRemark("销售-反审入库"); // 备注 |
| | | stockInRecord.setType(stockOutRecord.getType()); // 类型(合格/不合格) |
| | | stockInRecord.setSalesLedgerId(stockOutRecord.getSalesLedgerId()); // 销售订单ID |
| | | stockInRecord.setSalesLedgerProductId(stockOutRecord.getSalesLedgerProductId()); // 销售订单产品ID |
| | | |
| | | // 4.2 插入反审入库记录 |
| | | stockInRecordMapper.insert(stockInRecord); |
| | | |
| | | // 4.3 向库存表中增加相应数量 |
| | | // 向库存表中增加相应数量 |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setProductModelId(stockInRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockInRecord.getStockInNum()); |
| | | stockInventoryDto.setProductModelId(stockOutRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockOutRecord.getStockOutNum()); |
| | | stockInventoryMapper.updateAddStockInventory(stockInventoryDto); |
| | | } |
| | | |
| | | // 6. 删除所有出库记录 |
| | | stockOutRecordMapper.delete( |
| | | Wrappers.<StockOutRecord>lambdaQuery() |
| | | .eq(StockOutRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void markOrderCompleted(List<Long> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | throw new ServiceException("请选择要标记完成的订单"); |
| | | } |
| | | for (Long id : ids) { |
| | | SalesLedger ledger = salesLedgerMapper.selectById(id); |
| | | if (ledger == null) { |
| | | throw new ServiceException("订单不存在,无法标记完成"); |
| | | } |
| | | if (ledger.getReviewStatus() == null || ledger.getReviewStatus() != 1) { |
| | | throw new ServiceException("订单" + ledger.getSalesContractNo() + "不是已审核状态,无法标记完成"); |
| | | } |
| | | if (ledger.getOrderStatus() != null && ledger.getOrderStatus() == 1) { |
| | | throw new ServiceException("订单" + ledger.getSalesContractNo() + "已完成,无需重复标记"); |
| | | } |
| | | } |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .in(SalesLedger::getId, ids) |
| | | .set(SalesLedger::getOrderStatus, 1) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public void incrementPrintCount(Long id, String printType) { |
| | | if (id == null) { |
| | | throw new ServiceException("销售台账ID不能为空"); |
| | | } |
| | | if (printType == null || (!"label".equals(printType) && !"document".equals(printType))) { |
| | | throw new ServiceException("打印类型必须为 label 或 document"); |
| | | } |
| | | SalesLedger ledger = salesLedgerMapper.selectById(id); |
| | | if (ledger == null) { |
| | | throw new ServiceException("销售台账不存在"); |
| | | } |
| | | if ("label".equals(printType)) { |
| | | int currentCount = ledger.getLabelPrintCount() == null ? 0 : ledger.getLabelPrintCount(); |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .eq(SalesLedger::getId, id) |
| | | .set(SalesLedger::getLabelPrintCount, currentCount + 1) |
| | | ); |
| | | } else { |
| | | int currentCount = ledger.getDocumentPrintCount() == null ? 0 : ledger.getDocumentPrintCount(); |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .eq(SalesLedger::getId, id) |
| | | .set(SalesLedger::getDocumentPrintCount, currentCount + 1) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void exportWithProducts(HttpServletResponse response, SalesLedgerDto salesLedgerDto) { |
| | | try { |
| | | // 1. 查询销售台账列表(导出使用升序排序) |
| | | Page<SalesLedger> page = new Page<>(-1, -1); |
| | | // 使用 Wrappers 构建升序查询 |
| | | LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.<SalesLedger>lambdaQuery() |
| | | .orderByAsc(SalesLedger::getEntryDate) |
| | | .orderByAsc(SalesLedger::getId); |
| | | |
| | | // 添加查询条件 |
| | | if (salesLedgerDto.getCustomerName() != null && !salesLedgerDto.getCustomerName().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getCustomerName, salesLedgerDto.getCustomerName()); |
| | | } |
| | | if (salesLedgerDto.getSalesContractNo() != null && !salesLedgerDto.getSalesContractNo().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getSalesContractNo, salesLedgerDto.getSalesContractNo()); |
| | | } |
| | | if (salesLedgerDto.getProjectName() != null && !salesLedgerDto.getProjectName().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getProjectName, salesLedgerDto.getProjectName()); |
| | | } |
| | | if (salesLedgerDto.getEntryDateStart() != null && !salesLedgerDto.getEntryDateStart().isEmpty()) { |
| | | queryWrapper.ge(SalesLedger::getEntryDate, salesLedgerDto.getEntryDateStart()); |
| | | } |
| | | if (salesLedgerDto.getEntryDateEnd() != null && !salesLedgerDto.getEntryDateEnd().isEmpty()) { |
| | | queryWrapper.le(SalesLedger::getEntryDate, salesLedgerDto.getEntryDateEnd()); |
| | | } |
| | | if (salesLedgerDto.getDeliveryStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getDeliveryStatus, salesLedgerDto.getDeliveryStatus()); |
| | | } |
| | | if (salesLedgerDto.getStockStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getStockStatus, salesLedgerDto.getStockStatus()); |
| | | } |
| | | if (salesLedgerDto.getReviewStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getReviewStatus, salesLedgerDto.getReviewStatus()); |
| | | } |
| | | if (salesLedgerDto.getOrderStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getOrderStatus, salesLedgerDto.getOrderStatus()); |
| | | } |
| | | if (salesLedgerDto.getReviewStatusList() != null && !salesLedgerDto.getReviewStatusList().isEmpty()) { |
| | | queryWrapper.and(w -> w.in(SalesLedger::getReviewStatus, salesLedgerDto.getReviewStatusList()) |
| | | .or().isNull(SalesLedger::getReviewStatus)); |
| | | } |
| | | |
| | | List<SalesLedger> ledgerList = salesLedgerMapper.selectList(page, queryWrapper); |
| | | |
| | | // 2. 收集数据 |
| | | List<SalesLedgerExportDto> ledgerExportList = new ArrayList<>(); |
| | | List<SalesLedgerProductExportDto> productExportList = new ArrayList<>(); |
| | | |
| | | for (SalesLedger ledger : ledgerList) { |
| | | // 转换台账数据 |
| | | SalesLedgerExportDto ledgerDto = new SalesLedgerExportDto(); |
| | | ledgerDto.setSalesContractNo(ledger.getSalesContractNo()); |
| | | ledgerDto.setCustomerContractNo(ledger.getCustomerContractNo()); |
| | | ledgerDto.setProjectName(ledger.getProjectName()); |
| | | ledgerDto.setCustomerName(ledger.getCustomerName()); |
| | | ledgerDto.setSalesman(ledger.getSalesman()); |
| | | ledgerDto.setEntryPersonName(ledger.getEntryPersonName()); |
| | | ledgerDto.setEntryDate(ledger.getEntryDate()); |
| | | ledgerDto.setExecutionDate(ledger.getExecutionDate() != null ? |
| | | java.sql.Date.valueOf(ledger.getExecutionDate()) : null); |
| | | ledgerDto.setDeliveryDate(ledger.getDeliveryDate() != null ? |
| | | java.sql.Date.valueOf(ledger.getDeliveryDate()) : null); |
| | | ledgerDto.setContractAmount(ledger.getContractAmount()); |
| | | ledgerDto.setRemarks(ledger.getRemarks()); |
| | | ledgerDto.setCustomerRemarks(ledger.getCustomerRemarks()); |
| | | ledgerDto.setDeliveryStatusText(getDeliveryStatusText(ledger.getDeliveryStatus())); |
| | | ledgerDto.setStockStatusText(getStockStatusText(ledger.getStockStatus())); |
| | | ledgerDto.setReviewStatusText(getReviewStatusText(ledger.getReviewStatus())); |
| | | ledgerDto.setOrderStatusText(getOrderStatusText(ledger.getOrderStatus())); |
| | | ledgerExportList.add(ledgerDto); |
| | | |
| | | // 查询该台账的产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()) |
| | | .eq(SalesLedgerProduct::getType, 1) |
| | | ); |
| | | |
| | | for (SalesLedgerProduct product : products) { |
| | | SalesLedgerProductExportDto productDto = new SalesLedgerProductExportDto(); |
| | | productDto.setSalesContractNo(ledger.getSalesContractNo()); |
| | | productDto.setProductCategory(product.getProductCategory()); |
| | | productDto.setSpecificationModel(product.getSpecificationModel()); |
| | | productDto.setThickness(product.getThickness()); |
| | | productDto.setFloorCode(product.getFloorCode()); |
| | | productDto.setWidth(product.getWidth()); |
| | | productDto.setHeight(product.getHeight()); |
| | | productDto.setQuantity(product.getQuantity()); |
| | | productDto.setSettlePieceArea(product.getSettlePieceArea()); |
| | | productDto.setSettleTotalArea(product.getSettleTotalArea()); |
| | | productDto.setTaxInclusiveUnitPrice(product.getTaxInclusiveUnitPrice()); |
| | | productDto.setTaxRate(product.getTaxRate()); |
| | | productDto.setTaxInclusiveTotalPrice(product.getTaxInclusiveTotalPrice()); |
| | | productDto.setTaxExclusiveTotalPrice(product.getTaxExclusiveTotalPrice()); |
| | | productDto.setInvoiceType(product.getInvoiceType()); |
| | | productDto.setProcessRequirement(product.getProcessRequirement()); |
| | | productDto.setRemark(product.getRemark()); |
| | | productExportList.add(productDto); |
| | | } |
| | | } |
| | | |
| | | // 3. 使用ExcelUtil导出(内部会创建Workbook并写入响应) |
| | | // 先创建临时文件,再合并两个sheet |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("utf-8"); |
| | | String fileName = URLEncoder.encode("销售台账.xlsx", "utf-8").replaceAll("\\+", "%20"); |
| | | response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName); |
| | | |
| | | org.apache.poi.xssf.usermodel.XSSFWorkbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(); |
| | | |
| | | // Sheet1: 销售台账 - 手动填充 |
| | | fillSheetWithData(workbook, "销售台账", SalesLedgerExportDto.class, ledgerExportList); |
| | | |
| | | // Sheet2: 产品明细 - 手动填充 |
| | | fillSheetWithData(workbook, "产品明细", SalesLedgerProductExportDto.class, productExportList); |
| | | |
| | | workbook.write(response.getOutputStream()); |
| | | workbook.close(); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("导出销售台账失败", e); |
| | | throw new ServiceException("导出失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 手动填充Sheet数据 |
| | | */ |
| | | private <T> void fillSheetWithData(org.apache.poi.xssf.usermodel.XSSFWorkbook workbook, String sheetName, Class<T> clazz, List<T> dataList) throws Exception { |
| | | org.apache.poi.ss.usermodel.Sheet sheet = workbook.createSheet(sheetName); |
| | | |
| | | // 获取字段上的@Excel注解 |
| | | java.lang.reflect.Field[] fields = clazz.getDeclaredFields(); |
| | | List<java.lang.reflect.Field> excelFields = new ArrayList<>(); |
| | | for (java.lang.reflect.Field field : fields) { |
| | | com.ruoyi.framework.aspectj.lang.annotation.Excel excel = field.getAnnotation(com.ruoyi.framework.aspectj.lang.annotation.Excel.class); |
| | | if (excel != null) { |
| | | excelFields.add(field); |
| | | } |
| | | } |
| | | |
| | | // 创建表头 |
| | | org.apache.poi.ss.usermodel.Row headerRow = sheet.createRow(0); |
| | | org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle(); |
| | | headerStyle.setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.GREY_50_PERCENT.getIndex()); |
| | | headerStyle.setFillPattern(org.apache.poi.ss.usermodel.FillPatternType.SOLID_FOREGROUND); |
| | | headerStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER); |
| | | org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont(); |
| | | headerFont.setBold(true); |
| | | headerStyle.setFont(headerFont); |
| | | |
| | | for (int i = 0; i < excelFields.size(); i++) { |
| | | java.lang.reflect.Field field = excelFields.get(i); |
| | | field.setAccessible(true); |
| | | com.ruoyi.framework.aspectj.lang.annotation.Excel excel = field.getAnnotation(com.ruoyi.framework.aspectj.lang.annotation.Excel.class); |
| | | org.apache.poi.ss.usermodel.Cell cell = headerRow.createCell(i); |
| | | cell.setCellValue(excel.name()); |
| | | cell.setCellStyle(headerStyle); |
| | | sheet.setColumnWidth(i, 20 * 256); |
| | | } |
| | | |
| | | // 创建数据行 |
| | | org.apache.poi.ss.usermodel.CellStyle dataStyle = workbook.createCellStyle(); |
| | | dataStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER); |
| | | |
| | | for (int rowIndex = 0; rowIndex < dataList.size(); rowIndex++) { |
| | | T data = dataList.get(rowIndex); |
| | | org.apache.poi.ss.usermodel.Row row = sheet.createRow(rowIndex + 1); |
| | | for (int colIndex = 0; colIndex < excelFields.size(); colIndex++) { |
| | | java.lang.reflect.Field field = excelFields.get(colIndex); |
| | | field.setAccessible(true); |
| | | Object value = field.get(data); |
| | | org.apache.poi.ss.usermodel.Cell cell = row.createCell(colIndex); |
| | | if (value == null) { |
| | | cell.setCellValue(""); |
| | | } else if (value instanceof Number) { |
| | | cell.setCellValue(((Number) value).doubleValue()); |
| | | } else if (value instanceof Date) { |
| | | cell.setCellValue(new java.text.SimpleDateFormat("yyyy-MM-dd").format((Date) value)); |
| | | } else { |
| | | cell.setCellValue(value.toString()); |
| | | } |
| | | cell.setCellStyle(dataStyle); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String getDeliveryStatusText(Integer status) { |
| | | if (status == null) return "未知"; |
| | | switch (status) { |
| | | case 1: return "未发货"; |
| | | case 2: return "审批中"; |
| | | case 3: return "审批不通过"; |
| | | case 4: return "审批通过"; |
| | | case 5: return "已发货"; |
| | | case 6: return "部分发货"; |
| | | default: return "未知"; |
| | | } |
| | | } |
| | | |
| | | private String getStockStatusText(Integer status) { |
| | | if (status == null) return "未知"; |
| | | switch (status) { |
| | | case 0: return "未入库"; |
| | | case 1: return "部分入库"; |
| | | case 2: return "已入库"; |
| | | case 3: return "审批中"; |
| | | default: return "未知"; |
| | | } |
| | | } |
| | | |
| | | private String getReviewStatusText(Integer status) { |
| | | if (status == null) return "待审核"; |
| | | switch (status) { |
| | | case 0: return "待审核"; |
| | | case 1: return "已审核"; |
| | | case 2: return "已反审"; |
| | | default: return "待审核"; |
| | | } |
| | | } |
| | | |
| | | private String getOrderStatusText(Integer status) { |
| | | if (status == null || status == 0) return "进行中"; |
| | | switch (status) { |
| | | case 0: return "进行中"; |
| | | case 1: return "已完成"; |
| | | default: return "进行中"; |
| | | } |
| | | } |
| | | } |