| | |
| | | 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; |
| | |
| | | .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 "进行中"; |
| | | } |
| | | } |
| | | } |