| | |
| | | import com.ruoyi.sales.mapper.*; |
| | | import com.ruoyi.sales.pojo.*; |
| | | import com.ruoyi.sales.service.ISalesLedgerProcessRouteService; |
| | | import com.ruoyi.sales.service.ISalesLedgerProcessRouteRecordService; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductProcessBindService; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductProcessService; |
| | | import com.ruoyi.sales.service.ISalesLedgerService; |
| | |
| | | private final ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService; |
| | | |
| | | private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService; |
| | | private final ISalesLedgerProcessRouteRecordService salesLedgerProcessRouteRecordService; |
| | | |
| | | private final StockInventoryService stockInventoryService; |
| | | private final StockInRecordMapper stockInRecordMapper; |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void saleProcessBind(SalesLedgerProcessRoute salesLedgerProcessRoute) { |
| | | if (salesLedgerProcessRoute == null) { |
| | | public void saleProcessBind(SalesLedgerProcessRouteDto salesLedgerProcessRouteDto) { |
| | | if (salesLedgerProcessRouteDto == null) { |
| | | throw new ServiceException("绑定失败,数据不能为空"); |
| | | } |
| | | |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRoute.getSalesLedgerId()); |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRouteDto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("绑定失败,销售订单不存在"); |
| | | } |
| | | ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRoute.getProcessRouteId()); |
| | | ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRouteDto.getProcessRouteId()); |
| | | if (processRoute == null) { |
| | | throw new ServiceException("绑定失败,工艺路线不存在"); |
| | | } |
| | | // 清除已绑定的数据 |
| | | salesLedgerProcessRouteService.remove(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId())); |
| | | salesLedgerProcessRouteRecordService.remove(new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>().eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedger.getId())); |
| | | |
| | | // 将数据迁移到sales_ledger_process_route |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId())); |
| | |
| | | salesLedgerProcessRouteList.add(ledgerProcessRoute); |
| | | } |
| | | salesLedgerProcessRouteService.saveBatch(salesLedgerProcessRouteList); |
| | | |
| | | List<SalesLedgerProcessRoute> savedRoutes = salesLedgerProcessRouteService.list(new LambdaQueryWrapper<SalesLedgerProcessRoute>() |
| | | .eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId()) |
| | | .eq(SalesLedgerProcessRoute::getProcessRouteId, processRoute.getId())); |
| | | Map<Long, SalesLedgerProcessRoute> routeMap = savedRoutes.stream() |
| | | .filter(item -> item.getProcessRouteItemId() != null) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getProcessRouteItemId, item -> item, (a, b) -> a)); |
| | | |
| | | Map<Long, SalesLedgerProcessRouteRecord> inputRecordMap = new HashMap<>(); |
| | | if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteDto.getRecordList())) { |
| | | for (SalesLedgerProcessRouteRecord record : salesLedgerProcessRouteDto.getRecordList()) { |
| | | if (record != null && record.getProcessRouteItemId() != null) { |
| | | inputRecordMap.put(record.getProcessRouteItemId(), record); |
| | | } |
| | | } |
| | | } |
| | | |
| | | List<SalesLedgerProcessRouteRecord> routeRecordList = new ArrayList<>(); |
| | | for (ProcessRouteItem routeItem : routeItems) { |
| | | SalesLedgerProcessRoute route = routeMap.get(routeItem.getId()); |
| | | if (route == null || route.getId() == null) { |
| | | continue; |
| | | } |
| | | SalesLedgerProcessRouteRecord inputRecord = inputRecordMap.get(routeItem.getId()); |
| | | SalesLedgerProcessRouteRecord record = new SalesLedgerProcessRouteRecord(); |
| | | record.setSalesLedgerId(salesLedger.getId()); |
| | | record.setSalesLedgerProcessRouteId(route.getId()); |
| | | Integer isCompleted = inputRecord != null && inputRecord.getIsCompleted() != null ? inputRecord.getIsCompleted() : 0; |
| | | record.setIsCompleted(isCompleted); |
| | | record.setCompletedTime(Objects.equals(isCompleted, 1) ? LocalDateTime.now() : null); |
| | | routeRecordList.add(record); |
| | | } |
| | | salesLedgerProcessRouteRecordService.saveBatch(routeRecordList); |
| | | } |
| | | |
| | | /** |
| | |
| | | public SalesLedgerProcessRouteDto salesProcess(Long salesLedgerId) { |
| | | SalesLedgerProcessRouteDto dto = new SalesLedgerProcessRouteDto(); |
| | | List<SalesLedgerProcessRoute> list = baseMapper.selectSalesProcess(salesLedgerId); |
| | | List<SalesLedgerProcessRouteRecord> recordList = salesLedgerProcessRouteRecordService.list( |
| | | new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>() |
| | | .eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerId) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getId) |
| | | ); |
| | | if (CollectionUtils.isNotEmpty(list)) { |
| | | Long processRouteId = list.get(0).getProcessRouteId(); |
| | | ProcessRoute processRoute = processRouteMapper.selectById(processRouteId); |
| | |
| | | } |
| | | } |
| | | dto.setList(list); |
| | | if (CollectionUtils.isNotEmpty(list) && CollectionUtils.isNotEmpty(recordList)) { |
| | | Map<Long, Long> routeItemIdMap = list.stream() |
| | | .filter(item -> item.getId() != null && item.getProcessRouteItemId() != null) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, SalesLedgerProcessRoute::getProcessRouteItemId, (a, b) -> a)); |
| | | recordList.forEach(record -> { |
| | | if (record != null && record.getSalesLedgerProcessRouteId() != null) { |
| | | record.setProcessRouteItemId(routeItemIdMap.get(record.getSalesLedgerProcessRouteId())); |
| | | } |
| | | }); |
| | | } |
| | | dto.setRecordList(recordList); |
| | | return dto; |
| | | } |
| | | |
| | |
| | | .or().isNull(SalesLedger::getReviewStatus)); |
| | | } |
| | | |
| | | List<SalesLedger> ledgerList = salesLedgerMapper.selectList(page, queryWrapper); |
| | | IPage<SalesLedger> ledgerPage = salesLedgerMapper.selectPage(page, queryWrapper); |
| | | List<SalesLedger> ledgerList = ledgerPage.getRecords(); |
| | | |
| | | // 2. 收集数据 |
| | | List<SalesLedgerExportDto> ledgerExportList = new ArrayList<>(); |
| | |
| | | log.error("导出销售台账失败", e); |
| | | throw new ServiceException("导出失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void exportProcessRoute(HttpServletResponse response, List<Long> salesLedgerIds, String completedTimeStart, String completedTimeEnd) { |
| | | try { |
| | | if (CollectionUtils.isEmpty(salesLedgerIds)) { |
| | | throw new ServiceException("请选择要导出的销售台账"); |
| | | } |
| | | LocalDateTime startTime = parseCompletedTime(completedTimeStart); |
| | | LocalDateTime endTime = parseCompletedTime(completedTimeEnd); |
| | | if (startTime == null && endTime == null) { |
| | | startTime = LocalDate.now().atStartOfDay(); |
| | | endTime = LocalDateTime.now(); |
| | | } else { |
| | | if (startTime == null) { |
| | | startTime = LocalDate.now().atStartOfDay(); |
| | | } |
| | | if (endTime == null) { |
| | | endTime = LocalDateTime.now(); |
| | | } |
| | | } |
| | | |
| | | LambdaQueryWrapper<SalesLedgerProcessRouteRecord> queryWrapper = Wrappers.<SalesLedgerProcessRouteRecord>lambdaQuery() |
| | | .eq(SalesLedgerProcessRouteRecord::getIsCompleted, 1) |
| | | .ge(SalesLedgerProcessRouteRecord::getCompletedTime, startTime) |
| | | .le(SalesLedgerProcessRouteRecord::getCompletedTime, endTime) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getCompletedTime) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getId); |
| | | |
| | | if (CollectionUtils.isNotEmpty(salesLedgerIds)) { |
| | | queryWrapper.in(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerIds); |
| | | } |
| | | |
| | | List<SalesLedgerProcessRouteRecord> completedRoutes = salesLedgerProcessRouteRecordService.list(queryWrapper); |
| | | Map<Long, SalesLedger> salesLedgerMap = Collections.emptyMap(); |
| | | Map<Long, SalesLedgerProcessRoute> routeMap = Collections.emptyMap(); |
| | | Map<Long, ProcessRouteItem> processRouteItemMap = Collections.emptyMap(); |
| | | Map<Long, List<SalesLedgerProduct>> productMap = Collections.emptyMap(); |
| | | |
| | | if (CollectionUtils.isNotEmpty(completedRoutes)) { |
| | | List<Long> routeSalesLedgerIds = completedRoutes.stream() |
| | | .map(SalesLedgerProcessRouteRecord::getSalesLedgerId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | List<Long> salesLedgerProcessRouteIds = completedRoutes.stream() |
| | | .map(SalesLedgerProcessRouteRecord::getSalesLedgerProcessRouteId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isNotEmpty(routeSalesLedgerIds)) { |
| | | salesLedgerMap = salesLedgerMapper.selectBatchIds(routeSalesLedgerIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a)); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>() |
| | | .in(SalesLedgerProduct::getSalesLedgerId, routeSalesLedgerIds) |
| | | .eq(SalesLedgerProduct::getType, 1) |
| | | .orderByAsc(SalesLedgerProduct::getSalesLedgerId) |
| | | .orderByAsc(SalesLedgerProduct::getId)); |
| | | productMap = products.stream().collect(Collectors.groupingBy( |
| | | SalesLedgerProduct::getSalesLedgerId, |
| | | LinkedHashMap::new, |
| | | Collectors.toList() |
| | | )); |
| | | } |
| | | |
| | | if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteIds)) { |
| | | routeMap = salesLedgerProcessRouteService.listByIds(salesLedgerProcessRouteIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, item -> item, (a, b) -> a)); |
| | | List<Long> processRouteItemIds = routeMap.values().stream() |
| | | .map(SalesLedgerProcessRoute::getProcessRouteItemId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(processRouteItemIds)) { |
| | | processRouteItemMap = processRouteItemMapper.selectBatchIds(processRouteItemIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(ProcessRouteItem::getId, item -> item, (a, b) -> a)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Map<Long, List<SalesLedgerProcessRouteRecord>> routeGroupMap = new LinkedHashMap<>(); |
| | | for (SalesLedgerProcessRouteRecord record : completedRoutes) { |
| | | SalesLedgerProcessRoute route = routeMap.get(record.getSalesLedgerProcessRouteId()); |
| | | if (route == null || route.getProcessRouteItemId() == null) { |
| | | continue; |
| | | } |
| | | routeGroupMap.computeIfAbsent(route.getProcessRouteItemId(), k -> new ArrayList<>()).add(record); |
| | | } |
| | | |
| | | final Map<Long, ProcessRouteItem> finalProcessRouteItemMap = processRouteItemMap; |
| | | LinkedHashMap<String, List<List<Object>>> sheetMap = new LinkedHashMap<>(); |
| | | List<Long> orderedProcessRouteItemIds = routeGroupMap.keySet().stream() |
| | | .sorted((left, right) -> compareProcessRouteItem(left, right, finalProcessRouteItemMap)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | for (Long processRouteItemId : orderedProcessRouteItemIds) { |
| | | ProcessRouteItem processRouteItem = finalProcessRouteItemMap.get(processRouteItemId); |
| | | String sheetName = buildUniqueSheetName(sheetMap, processRouteItem, processRouteItemId); |
| | | List<List<Object>> sheetData = new ArrayList<>(); |
| | | sheetData.add(buildProcessRouteHeader()); |
| | | |
| | | for (SalesLedgerProcessRouteRecord route : routeGroupMap.getOrDefault(processRouteItemId, Collections.emptyList())) { |
| | | SalesLedger salesLedger = salesLedgerMap.get(route.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | continue; |
| | | } |
| | | List<SalesLedgerProduct> products = productMap.getOrDefault(salesLedger.getId(), Collections.emptyList()); |
| | | if (CollectionUtils.isEmpty(products)) { |
| | | sheetData.add(buildProcessRouteRow(salesLedger, null, route)); |
| | | continue; |
| | | } |
| | | for (SalesLedgerProduct product : products) { |
| | | sheetData.add(buildProcessRouteRow(salesLedger, product, route)); |
| | | } |
| | | } |
| | | |
| | | if (sheetData.size() == 1) { |
| | | sheetData.add(Arrays.asList("", "", "", "", "", "", "", "", "")); |
| | | } |
| | | sheetMap.put(sheetName, sheetData); |
| | | } |
| | | |
| | | if (sheetMap.isEmpty()) { |
| | | List<List<Object>> sheetData = new ArrayList<>(); |
| | | sheetData.add(buildProcessRouteHeader()); |
| | | sheetData.add(Arrays.asList("", "", "", "", "", "", "")); |
| | | sheetMap.put("工艺路线", sheetData); |
| | | } |
| | | |
| | | com.ruoyi.common.utils.excel.ExcelUtils.exportManySheet(response, "销售台账工艺路线导出", sheetMap); |
| | | } catch (Exception e) { |
| | | log.error("导出售后台账工艺路线失败", e); |
| | | throw new ServiceException("导出售后台账工艺路线失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private LocalDateTime parseCompletedTime(String value) { |
| | | if (!StringUtils.hasText(value)) { |
| | | return null; |
| | | } |
| | | String text = value.trim(); |
| | | try { |
| | | return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); |
| | | } catch (Exception ex) { |
| | | try { |
| | | return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); |
| | | } catch (Exception ignored) { |
| | | return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private int compareProcessRouteItem(Long left, Long right, Map<Long, ProcessRouteItem> processRouteItemMap) { |
| | | ProcessRouteItem leftItem = processRouteItemMap.get(left); |
| | | ProcessRouteItem rightItem = processRouteItemMap.get(right); |
| | | int leftSort = leftItem != null && leftItem.getDragSort() != null ? leftItem.getDragSort() : Integer.MAX_VALUE; |
| | | int rightSort = rightItem != null && rightItem.getDragSort() != null ? rightItem.getDragSort() : Integer.MAX_VALUE; |
| | | if (leftSort != rightSort) { |
| | | return Integer.compare(leftSort, rightSort); |
| | | } |
| | | String leftName = leftItem != null && StringUtils.hasText(leftItem.getProcessName()) ? leftItem.getProcessName() : ""; |
| | | String rightName = rightItem != null && StringUtils.hasText(rightItem.getProcessName()) ? rightItem.getProcessName() : ""; |
| | | int nameCompare = leftName.compareTo(rightName); |
| | | if (nameCompare != 0) { |
| | | return nameCompare; |
| | | } |
| | | return Long.compare(left, right); |
| | | } |
| | | |
| | | private List<Object> buildProcessRouteHeader() { |
| | | return Arrays.asList("日期", "订单编号", "客户名称", "规格", "数量", "面积", "是否是工程"); |
| | | } |
| | | |
| | | private List<Object> buildProcessRouteRow(SalesLedger salesLedger, SalesLedgerProduct product, SalesLedgerProcessRouteRecord route) { |
| | | List<Object> row = new ArrayList<>(); |
| | | row.add(salesLedger.getEntryDate() == null ? "" : DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, salesLedger.getEntryDate())); |
| | | row.add(salesLedger.getSalesContractNo()); |
| | | row.add(salesLedger.getCustomerName()); |
| | | row.add(product == null ? "" : product.getSpecificationModel()); |
| | | row.add(product == null ? "" : product.getQuantity()); |
| | | row.add(product == null ? "" : resolveExportArea(product)); |
| | | row.add(""); |
| | | return row; |
| | | } |
| | | |
| | | private BigDecimal resolveExportArea(SalesLedgerProduct product) { |
| | | if (product == null) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | if (product.getSettleTotalArea() != null) { |
| | | return product.getSettleTotalArea(); |
| | | } |
| | | if (product.getActualTotalArea() != null) { |
| | | return product.getActualTotalArea(); |
| | | } |
| | | BigDecimal qty = product.getQuantity() == null ? BigDecimal.ONE : product.getQuantity(); |
| | | if (product.getSettlePieceArea() != null) { |
| | | return product.getSettlePieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | if (product.getActualPieceArea() != null) { |
| | | return product.getActualPieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | if (product.getWidth() != null && product.getHeight() != null) { |
| | | BigDecimal area = product.getWidth().multiply(product.getHeight()) |
| | | .divide(new BigDecimal("1000000"), 2, RoundingMode.HALF_UP); |
| | | return area.multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | return BigDecimal.ZERO; |
| | | } |
| | | |
| | | private String buildUniqueSheetName(Map<String, List<List<Object>>> sheetMap, ProcessRouteItem processRouteItem, Long processRouteItemId) { |
| | | String baseName = processRouteItem != null && StringUtils.hasText(processRouteItem.getProcessName()) |
| | | ? processRouteItem.getProcessName() |
| | | : "工序" + processRouteItemId; |
| | | baseName = sanitizeSheetName(baseName); |
| | | String sheetName = baseName; |
| | | int suffix = 2; |
| | | while (sheetMap.containsKey(sheetName)) { |
| | | String suffixText = "_" + suffix++; |
| | | int maxBaseLength = 31 - suffixText.length(); |
| | | String trimmedBase = baseName.length() > maxBaseLength ? baseName.substring(0, maxBaseLength) : baseName; |
| | | sheetName = trimmedBase + suffixText; |
| | | } |
| | | return sheetName; |
| | | } |
| | | |
| | | private String sanitizeSheetName(String sheetName) { |
| | | if (!StringUtils.hasText(sheetName)) { |
| | | return "工艺路线"; |
| | | } |
| | | String sanitized = sheetName.replaceAll("[\\\\/?*\\[\\]:]", "_").trim(); |
| | | if (sanitized.isEmpty()) { |
| | | sanitized = "工艺路线"; |
| | | } |
| | | return sanitized.length() > 31 ? sanitized.substring(0, 31) : sanitized; |
| | | } |
| | | |
| | | /** |
| | |
| | | default: return "进行中"; |
| | | } |
| | | } |
| | | } |
| | | } |