| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.account.service.AccountIncomeService; |
| | | import com.ruoyi.approve.service.IApproveProcessService; |
| | | import com.ruoyi.approve.vo.ApproveProcessVO; |
| | | import com.ruoyi.approve.pojo.ApproveProcess; |
| | | import com.ruoyi.common.enums.ApproveTypeEnum; |
| | | import com.ruoyi.basic.mapper.CustomerMapper; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.Customer; |
| | | import com.ruoyi.basic.pojo.CustomerRegions; |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.basic.service.ICustomerRegionsService; |
| | | import com.ruoyi.common.enums.FileNameType; |
| | | import com.ruoyi.common.enums.SaleEnum; |
| | | import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockOutUnQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | |
| | | 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.other.pojo.TempFile; |
| | | import com.ruoyi.production.mapper.*; |
| | |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; |
| | | import com.ruoyi.quality.mapper.QualityInspectMapper; |
| | |
| | | import com.ruoyi.sales.service.ISalesLedgerProductProcessService; |
| | | import com.ruoyi.sales.service.ISalesLedgerService; |
| | | import com.ruoyi.stock.dto.StockInventoryDto; |
| | | import com.ruoyi.stock.mapper.StockInRecordMapper; |
| | | import com.ruoyi.stock.mapper.StockOutRecordMapper; |
| | | import com.ruoyi.stock.pojo.StockInRecord; |
| | | import com.ruoyi.stock.pojo.StockOutRecord; |
| | | import com.ruoyi.stock.service.StockInRecordService; |
| | | import com.ruoyi.stock.service.StockInventoryService; |
| | | import com.ruoyi.stock.service.StockOutRecordService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.io.FilenameUtils; |
| | |
| | | import java.nio.file.StandardCopyOption; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.time.YearMonth; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | |
| | | private static final String LOCK_PREFIX = "contract_no_lock:"; |
| | | private static final long LOCK_WAIT_TIMEOUT = 10; // 锁等待超时时间(秒) |
| | | private static final long LOCK_EXPIRE_TIME = 30; // 锁自动过期时间(秒) |
| | | private static final int INBOUND_BIZ_TYPE_WEB = 1; |
| | | private static final int INBOUND_BIZ_TYPE_SCAN_QUALIFIED = 2; |
| | | private static final int INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED = 3; |
| | | private final AccountIncomeService accountIncomeService; |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | private final CustomerMapper customerMapper; |
| | |
| | | private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService; |
| | | |
| | | private final StockInventoryService stockInventoryService; |
| | | private final StockInRecordMapper stockInRecordMapper; |
| | | private final StockOutRecordMapper stockOutRecordMapper; |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockOutRecordService stockOutRecordService; |
| | | private final StockUtils stockUtils; |
| | | @Autowired |
| | | private IApproveProcessService approveProcessService; |
| | | |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper); |
| | | Map<Long, ProductModel> productModelMap = Collections.emptyMap(); |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | List<Long> productModelIds = products.stream() |
| | | .map(SalesLedgerProduct::getProductModelId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | List<Long> productModelIds = products.stream().map(SalesLedgerProduct::getProductModelId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(productModelIds)) { |
| | | List<ProductModel> productModels = productModelMapper.selectBatchIds(productModelIds); |
| | | if (CollectionUtils.isNotEmpty(productModels)) { |
| | |
| | | product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); |
| | | product.setRegisterDate(LocalDateTime.now()); |
| | | // 发货信息 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, product.getId()) |
| | | .orderByDesc(ShippingInfo::getCreateTime) |
| | | .last("limit 1")); |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerProductId, product.getId()).orderByDesc(ShippingInfo::getCreateTime).last("limit 1")); |
| | | if (shippingInfo != null) { |
| | | product.setShippingStatus(shippingInfo.getStatus()); |
| | | } |
| | | // 加工明细,先查bind表获取该产品关联的工序及数量 |
| | | List<SalesLedgerProductProcessBind> bindList = salesLedgerProductProcessBindService.list( |
| | | new LambdaQueryWrapper<SalesLedgerProductProcessBind>() |
| | | .eq(SalesLedgerProductProcessBind::getSalesLedgerProductId, product.getId())); |
| | | List<SalesLedgerProductProcessBind> bindList = salesLedgerProductProcessBindService.list(new LambdaQueryWrapper<SalesLedgerProductProcessBind>().eq(SalesLedgerProductProcessBind::getSalesLedgerProductId, product.getId())); |
| | | if (!bindList.isEmpty()) { |
| | | List<Integer> processIds = bindList.stream() |
| | | .map(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId) |
| | | .collect(Collectors.toList()); |
| | | Map<Integer, Integer> processQuantityMap = bindList.stream() |
| | | .collect(Collectors.toMap( |
| | | SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, |
| | | SalesLedgerProductProcessBind::getQuantity, |
| | | (a, b) -> a)); |
| | | List<Integer> processIds = bindList.stream().map(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId).collect(Collectors.toList()); |
| | | Map<Integer, Integer> processQuantityMap = bindList.stream().collect(Collectors.toMap(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, SalesLedgerProductProcessBind::getQuantity, (a, b) -> a)); |
| | | List<SalesLedgerProductProcess> processList = salesLedgerProductProcessService.listByIds(processIds); |
| | | processList.forEach(p -> p.setQuantity(processQuantityMap.get(p.getId()))); |
| | | product.setSalesProductProcessList(processList); |
| | |
| | | product.setActualTotalArea(pieceArea.multiply(quantity).setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | product.fillRemainingQuantity(); |
| | | } |
| | | |
| | | // 3.查询上传文件 |
| | | LambdaQueryWrapper<CommonFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>(); |
| | | salesLedgerFileWrapper.eq(CommonFile::getCommonId, salesLedger.getId()) |
| | | .eq(CommonFile::getType, FileNameType.SALE.getValue()); |
| | | salesLedgerFileWrapper.eq(CommonFile::getCommonId, salesLedger.getId()).eq(CommonFile::getType, FileNameType.SALE.getValue()); |
| | | List<CommonFile> salesLedgerFiles = commonFileMapper.selectList(salesLedgerFileWrapper); |
| | | |
| | | // 4. 转换 DTO |
| | |
| | | List<Map<String, Object>> result = salesLedgerMapper.selectMaps(queryWrapper); |
| | | |
| | | // 将下划线命名转换为驼峰命名 |
| | | return result.stream().map(map -> map.entrySet().stream() |
| | | .collect(Collectors.toMap( |
| | | entry -> underlineToCamel(entry.getKey()), |
| | | Map.Entry::getValue)) |
| | | ).collect(Collectors.toList()); |
| | | return result.stream().map(map -> map.entrySet().stream().collect(Collectors.toMap(entry -> underlineToCamel(entry.getKey()), Map.Entry::getValue))).collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // 执行查询并计算总和 |
| | | List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(queryWrapper); |
| | | |
| | | BigDecimal totalContractAmount = salesLedgers.stream() |
| | | .map(SalesLedger::getContractAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal totalContractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | return totalContractAmount; |
| | | } |
| | |
| | | public List getTopFiveList() { |
| | | // 查询原始数据 |
| | | LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery(); |
| | | queryWrapper.select(SalesLedger::getCustomerId, |
| | | SalesLedger::getCustomerName, |
| | | SalesLedger::getContractAmount) |
| | | .orderByDesc(SalesLedger::getContractAmount); |
| | | queryWrapper.select(SalesLedger::getCustomerId, SalesLedger::getCustomerName, SalesLedger::getContractAmount).orderByDesc(SalesLedger::getContractAmount); |
| | | List<SalesLedger> records = salesLedgerMapper.selectList(queryWrapper); |
| | | |
| | | // 按客户ID分组并聚合金额 |
| | | Map<Long, GroupedCustomer> groupedMap = new LinkedHashMap<>(); // 使用LinkedHashMap保持排序 |
| | | for (SalesLedger record : records) { |
| | | groupedMap.computeIfAbsent(record.getCustomerId(), |
| | | k -> new GroupedCustomer(record.getCustomerId(), record.getCustomerName())) |
| | | .addAmount(record.getContractAmount()); |
| | | groupedMap.computeIfAbsent(record.getCustomerId(), k -> new GroupedCustomer(record.getCustomerId(), record.getCustomerName())).addAmount(record.getContractAmount()); |
| | | } |
| | | |
| | | // 转换为结果列表并取前5 |
| | | return groupedMap.values().stream() |
| | | .sorted(Comparator.comparing(GroupedCustomer::getTotalAmount).reversed()) |
| | | .limit(5) |
| | | .map(customer -> { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("customerId", customer.getCustomerId()); |
| | | result.put("customerName", customer.getCustomerName()); |
| | | result.put("totalAmount", customer.getTotalAmount()); |
| | | return result; |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | return groupedMap.values().stream().sorted(Comparator.comparing(GroupedCustomer::getTotalAmount).reversed()).limit(5).map(customer -> { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("customerId", customer.getCustomerId()); |
| | | result.put("customerName", customer.getCustomerName()); |
| | | result.put("totalAmount", customer.getTotalAmount()); |
| | | return result; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | // 回款金额 |
| | | LambdaQueryWrapper<ReceiptPayment> receiptPaymentQuery = new LambdaQueryWrapper<>(); |
| | | receiptPaymentQuery |
| | | .ge(ReceiptPayment::getCreateTime, startTime) |
| | | .le(ReceiptPayment::getCreateTime, endTime); |
| | | receiptPaymentQuery.ge(ReceiptPayment::getCreateTime, startTime).le(ReceiptPayment::getCreateTime, endTime); |
| | | |
| | | List<ReceiptPayment> receiptPayments = |
| | | receiptPaymentMapper.selectList(receiptPaymentQuery); |
| | | List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(receiptPaymentQuery); |
| | | |
| | | BigDecimal receiptAmount = receiptPayments.stream() |
| | | .map(ReceiptPayment::getReceiptPaymentAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal receiptAmount = receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | // 开票金额 |
| | | LambdaQueryWrapper<InvoiceLedger> invoiceLedgerQuery = new LambdaQueryWrapper<>(); |
| | | invoiceLedgerQuery |
| | | .ge(InvoiceLedger::getCreateTime, startTime) |
| | | .le(InvoiceLedger::getCreateTime, endTime); |
| | | invoiceLedgerQuery.ge(InvoiceLedger::getCreateTime, startTime).le(InvoiceLedger::getCreateTime, endTime); |
| | | |
| | | List<InvoiceLedger> invoiceLedgers = |
| | | invoiceLedgerMapper.selectList(invoiceLedgerQuery); |
| | | List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(invoiceLedgerQuery); |
| | | |
| | | BigDecimal invoiceAmount = invoiceLedgers.stream() |
| | | .map(InvoiceLedger::getInvoiceTotal) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal invoiceAmount = invoiceLedgers.stream().map(InvoiceLedger::getInvoiceTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | MonthlyAmountDto dto = new MonthlyAmountDto(); |
| | | dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"))); |
| | |
| | | |
| | | @Override |
| | | public IPage<SalesLedger> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) { |
| | | return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto); |
| | | IPage<SalesLedger> iPage = salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto); |
| | | |
| | | if (CollectionUtils.isEmpty(iPage.getRecords())) { |
| | | return iPage; |
| | | } |
| | | |
| | | List<Long> salesLedgerIds = iPage.getRecords().stream().map(SalesLedger::getId).collect(Collectors.toList()); |
| | | |
| | | boolean hasWidthHeightFilter = salesLedgerDto.getWidth() != null || salesLedgerDto.getHeight() != null; |
| | | Map<Long, List<SalesLedgerProduct>> matchedProductsMap = Collections.emptyMap(); |
| | | if (hasWidthHeightFilter) { |
| | | LambdaQueryWrapper<SalesLedgerProduct> productQueryWrapper = new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds).eq(SalesLedgerProduct::getType, 1); |
| | | if (salesLedgerDto.getWidth() != null) { |
| | | productQueryWrapper.eq(SalesLedgerProduct::getWidth, salesLedgerDto.getWidth()); |
| | | } |
| | | if (salesLedgerDto.getHeight() != null) { |
| | | productQueryWrapper.eq(SalesLedgerProduct::getHeight, salesLedgerDto.getHeight()); |
| | | } |
| | | List<SalesLedgerProduct> matchedProducts = salesLedgerProductMapper.selectList(productQueryWrapper); |
| | | matchedProductsMap = CollectionUtils.isEmpty(matchedProducts) ? Collections.emptyMap() : matchedProducts.stream().collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId)); |
| | | } |
| | | |
| | | List<SalesLedgerProductTotalsDto> productTotals = salesLedgerProductMapper.selectSalesLedgerProductTotals(salesLedgerIds, 1); |
| | | Map<Long, SalesLedgerProductTotalsDto> productTotalsMap = CollectionUtils.isEmpty(productTotals) ? Collections.emptyMap() : productTotals.stream().filter(t -> t.getSalesLedgerId() != null).collect(Collectors.toMap(SalesLedgerProductTotalsDto::getSalesLedgerId, Function.identity(), (a, b) -> a)); |
| | | |
| | | List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds); |
| | | if (CollectionUtils.isEmpty(invoiceLedgerDtoList)) { |
| | | invoiceLedgerDtoList = Collections.emptyList(); |
| | | } |
| | | |
| | | Map<Long, BigDecimal> invoiceTotals = invoiceLedgerDtoList.stream().filter(dto -> dto.getSalesLedgerId() != null && dto.getInvoiceTotal() != null).collect(Collectors.toMap(dto -> dto.getSalesLedgerId().longValue(), InvoiceLedgerDto::getInvoiceTotal, BigDecimal::add)); |
| | | |
| | | List<ReceiptPayment> receiptPayments = Collections.emptyList(); |
| | | if (!CollectionUtils.isEmpty(salesLedgerIds)) { |
| | | receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>().in(ReceiptPayment::getSalesLedgerId, salesLedgerIds)); |
| | | } |
| | | |
| | | Map<Long, BigDecimal> receiptTotals = new HashMap<>(); |
| | | if (!CollectionUtils.isEmpty(receiptPayments)) { |
| | | for (ReceiptPayment receiptPayment : receiptPayments) { |
| | | if (receiptPayment.getSalesLedgerId() != null && receiptPayment.getReceiptPaymentAmount() != null) { |
| | | receiptTotals.merge(receiptPayment.getSalesLedgerId(), receiptPayment.getReceiptPaymentAmount(), BigDecimal::add); |
| | | } |
| | | } |
| | | } |
| | | |
| | | for (SalesLedger salesLedger : iPage.getRecords()) { |
| | | Long ledgerId = salesLedger.getId(); |
| | | |
| | | SalesLedgerProductTotalsDto totals = productTotalsMap.get(ledgerId); |
| | | if (totals != null) { |
| | | salesLedger.setProductTotalQuantity(totals.getTotalQuantity() != null ? totals.getTotalQuantity() : BigDecimal.ZERO); |
| | | salesLedger.setProductTotalArea(totals.getTotalArea() != null ? totals.getTotalArea() : BigDecimal.ZERO); |
| | | } else { |
| | | salesLedger.setProductTotalQuantity(BigDecimal.ZERO); |
| | | salesLedger.setProductTotalArea(BigDecimal.ZERO); |
| | | } |
| | | if (hasWidthHeightFilter) { |
| | | salesLedger.setMatchedProducts(matchedProductsMap.getOrDefault(ledgerId, Collections.emptyList())); |
| | | } |
| | | |
| | | BigDecimal contractAmount = salesLedger.getContractAmount() == null ? BigDecimal.ZERO : salesLedger.getContractAmount(); |
| | | BigDecimal invoiceTotal = invoiceTotals.getOrDefault(ledgerId, BigDecimal.ZERO); |
| | | BigDecimal receiptPaymentAmountTotal = receiptTotals.getOrDefault(ledgerId, BigDecimal.ZERO); |
| | | |
| | | BigDecimal noInvoiceAmountTotal = contractAmount.subtract(invoiceTotal); |
| | | if (noInvoiceAmountTotal.compareTo(BigDecimal.ZERO) < 0) { |
| | | noInvoiceAmountTotal = BigDecimal.ZERO; |
| | | } |
| | | |
| | | BigDecimal noReceiptPaymentAmountTotal = invoiceTotal.subtract(receiptPaymentAmountTotal); |
| | | if (noReceiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) < 0) { |
| | | noReceiptPaymentAmountTotal = BigDecimal.ZERO; |
| | | } |
| | | |
| | | salesLedger.setNoInvoiceAmountTotal(noInvoiceAmountTotal); |
| | | salesLedger.setInvoiceTotal(invoiceTotal); |
| | | salesLedger.setReceiptPaymentAmountTotal(receiptPaymentAmountTotal); |
| | | salesLedger.setNoReceiptAmount(noReceiptPaymentAmountTotal); |
| | | |
| | | boolean hasInvoiceOperation = invoiceTotal.compareTo(BigDecimal.ZERO) > 0; |
| | | boolean hasReceiptOperation = receiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) > 0; |
| | | salesLedger.setIsEdit(!(hasInvoiceOperation || hasReceiptOperation)); |
| | | } |
| | | |
| | | if (salesLedgerDto.getStatus() != null && salesLedgerDto.getStatus()) { |
| | | iPage.getRecords().removeIf(salesLedger -> Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00"))); |
| | | iPage.setTotal(iPage.getRecords().size()); |
| | | } |
| | | |
| | | return iPage; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult importData(MultipartFile file) { |
| | | public void importData(MultipartFile file) { |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | try { |
| | | InputStream inputStream = file.getInputStream(); |
| | | ExcelUtil<SalesLedgerImportDto> salesLedgerImportDtoExcelUtil = new ExcelUtil<>(SalesLedgerImportDto.class); |
| | | Map<String, List<SalesLedgerImportDto>> stringListMap = salesLedgerImportDtoExcelUtil.importExcelMultiSheet(Arrays.asList("销售台账数据", "销售产品数据"), inputStream, 0); |
| | | if (CollectionUtils.isEmpty(stringListMap)) return AjaxResult.error("销售表格为空!"); |
| | | // 业务层合并 |
| | | List<SalesLedgerImportDto> salesLedgerImportDtoList = stringListMap.get("销售台账数据"); |
| | | if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return AjaxResult.error("销售台账数据为空!"); |
| | | List<SalesLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("销售产品数据"); |
| | | if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return AjaxResult.error("销售产品数据为空!"); |
| | | // 客户数据 |
| | | List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName, |
| | | salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList()))); |
| | | List<Map<String, Object>> list = productModelMapper.getProductAndModelList(); |
| | | // 录入人数据 |
| | | List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName, |
| | | salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList()))); |
| | | for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) { |
| | | SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>() |
| | | .eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo()) |
| | | .last("LIMIT 1")); |
| | | if (salesLedger1 != null) { |
| | | throw new ServiceException("导入失败:合同号 [" + salesLedgerImportDto.getSalesContractNo() + "] 已存在,请检查后重新导入"); |
| | | |
| | | Map<String, List<SalesLedgerImportDto>> stringListMap; |
| | | try (InputStream inputStream = file.getInputStream()) { |
| | | ExcelUtil<SalesLedgerImportDto> excelUtil = new ExcelUtil<>(SalesLedgerImportDto.class); |
| | | stringListMap = excelUtil.importExcelMultiSheet(Arrays.asList("销售台账数据", "销售产品数据"), inputStream, 0); |
| | | } catch (IOException e) { |
| | | log.error("销售台账导入失败:读取/解析Excel异常", e); |
| | | throw new ServiceException("导入失败:读取/解析Excel异常"); |
| | | } catch (Exception e) { |
| | | log.error("销售台账导入失败:解析Excel异常", e); |
| | | throw new ServiceException("导入失败:解析Excel异常"); |
| | | } |
| | | |
| | | if (CollectionUtils.isEmpty(stringListMap)) { |
| | | throw new ServiceException("导入失败,销售表格为空"); |
| | | } |
| | | // 业务层合并 |
| | | List<SalesLedgerImportDto> salesLedgerImportDtoList = stringListMap.get("销售台账数据"); |
| | | if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) { |
| | | throw new ServiceException("导入失败,销售台账数据为空"); |
| | | } |
| | | List<SalesLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("销售产品数据"); |
| | | if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) { |
| | | throw new ServiceException("导入失败,销售产品数据为空"); |
| | | } |
| | | // 客户数据 |
| | | List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName, salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList()))); |
| | | List<Map<String, Object>> list = productModelMapper.getProductAndModelList(); |
| | | // 录入人数据 |
| | | List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName, salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList()))); |
| | | for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) { |
| | | SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo()).last("LIMIT 1")); |
| | | if (salesLedger1 != null) { |
| | | throw new ServiceException("导入失败:合同号 [" + salesLedgerImportDto.getSalesContractNo() + "] 已存在,请检查后重新导入"); |
| | | } |
| | | SalesLedger salesLedger = new SalesLedger(); |
| | | BeanUtils.copyProperties(salesLedgerImportDto, salesLedger); |
| | | // 校验:签订日期、录入日期不能为空 |
| | | if (salesLedgerImportDto.getExecutionDate() == null) { |
| | | throw new ServiceException("导入失败:合同号[" + salesLedgerImportDto.getSalesContractNo() + "] 签订日期不能为空"); |
| | | } |
| | | if (salesLedgerImportDto.getEntryDate() == null) { |
| | | throw new ServiceException("导入失败:合同号[" + salesLedgerImportDto.getSalesContractNo() + "] 录入日期不能为空"); |
| | | } |
| | | salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate())); |
| | | |
| | | LocalDate expectedDeliveryDate = DateUtils.toLocalDate(salesLedgerImportDto.getEntryDate()).plusDays(7); |
| | | LocalDate importDeliveryDate = salesLedgerImportDto.getDeliveryDate() == null ? null : DateUtils.toLocalDate(salesLedgerImportDto.getDeliveryDate()); |
| | | // 交付日期为空则默认取录入日期后7天 |
| | | salesLedger.setDeliveryDate(importDeliveryDate == null ? expectedDeliveryDate : importDeliveryDate); |
| | | // 通过客户名称查询客户ID,客户合同号 |
| | | salesLedger.setCustomerId(customers.stream().filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())).findFirst().map(Customer::getId).orElse(null)); |
| | | salesLedger.setCustomerContractNo(customers.stream().filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())).findFirst().map(Customer::getTaxpayerIdentificationNumber).orElse(null)); |
| | | Long aLong = sysUsers.stream().filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson())).findFirst().map(SysUser::getUserId).orElse(null); |
| | | if (aLong == null) { |
| | | throw new ServiceException("录入人:" + salesLedger.getEntryPerson() + ",无对应用户!"); |
| | | } |
| | | salesLedger.setEntryPerson(aLong.toString()); |
| | | // 销售产品数据绑定,通过销售单号获取对应销售产品数据 |
| | | List<SalesLedgerProductImportDto> salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream().filter(salesLedgerProductImportDto -> salesLedgerProductImportDto.getSalesContractNo().equals(salesLedger.getSalesContractNo())).collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(salesLedgerProductImportDtos)) { |
| | | throw new ServiceException("销售单号:" + salesLedgerImportDto.getSalesContractNo() + ",无对应产品数据!"); |
| | | } |
| | | // 发货状态 |
| | | salesLedger.setDeliveryStatus(1); |
| | | salesLedger.setContractAmount(BigDecimal.ZERO); |
| | | salesLedgerMapper.insert(salesLedger); |
| | | BigDecimal contractAmount = BigDecimal.ZERO; |
| | | |
| | | for (SalesLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { |
| | | SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct); |
| | | salesLedgerProduct.setFloorCode(salesLedgerProductImportDto.getFloorNo()); |
| | | salesLedgerProduct.setProcessRequirement(salesLedgerProductImportDto.getProcessingRequirements()); |
| | | salesLedgerProduct.setRemark(salesLedgerProductImportDto.getRemarks()); |
| | | salesLedgerProduct.setSalesLedgerId(salesLedger.getId()); |
| | | salesLedgerProduct.setType(1); |
| | | |
| | | BigDecimal quantity = defaultDecimal(salesLedgerProduct.getQuantity()); |
| | | BigDecimal width = defaultDecimal(salesLedgerProduct.getWidth()); |
| | | BigDecimal height = defaultDecimal(salesLedgerProduct.getHeight()); |
| | | BigDecimal taxRateRaw = salesLedgerProduct.getTaxRate(); |
| | | BigDecimal taxRate = defaultDecimal(taxRateRaw); |
| | | BigDecimal unitPrice = defaultDecimal(salesLedgerProduct.getTaxInclusiveUnitPrice()); |
| | | |
| | | // 导入限制:宽/高/数量/金额(单价)/税率 不能为0或负数 |
| | | String locate = buildImportLocate(salesLedger.getSalesContractNo(), salesLedgerProductImportDto); |
| | | assertPositive(quantity, "数量", locate); |
| | | assertPositive(width, "宽(mm)", locate); |
| | | assertPositive(height, "高(mm)", locate); |
| | | assertPositive(unitPrice, "含税单价", locate); |
| | | assertNonNegative(taxRateRaw, "税率", locate); |
| | | |
| | | BigDecimal actualPieceArea = BigDecimal.ZERO; |
| | | if (width.compareTo(BigDecimal.ZERO) > 0 && height.compareTo(BigDecimal.ZERO) > 0) { |
| | | actualPieceArea = width.multiply(height).divide(new BigDecimal("1000000"), 4, RoundingMode.HALF_UP); |
| | | } |
| | | SalesLedger salesLedger = new SalesLedger(); |
| | | BeanUtils.copyProperties(salesLedgerImportDto, salesLedger); |
| | | salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate())); |
| | | // 通过客户名称查询客户ID,客户合同号 |
| | | salesLedger.setCustomerId(customers.stream() |
| | | .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())) |
| | | .findFirst() |
| | | .map(Customer::getId) |
| | | .orElse(null)); |
| | | salesLedger.setCustomerContractNo(customers.stream() |
| | | .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())) |
| | | .findFirst() |
| | | .map(Customer::getTaxpayerIdentificationNumber) |
| | | .orElse(null)); |
| | | Long aLong = sysUsers.stream() |
| | | .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson())) |
| | | .findFirst() |
| | | .map(SysUser::getUserId) |
| | | .orElse(null); |
| | | if (aLong == null) |
| | | throw new ServiceException("录入人:" + salesLedger.getEntryPerson() + ",无对应用户!"); |
| | | salesLedger.setEntryPerson(aLong.toString()); |
| | | // 销售产品数据绑定,通过销售单号获取对应销售产品数据 |
| | | List<SalesLedgerProductImportDto> salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream() |
| | | .filter(salesLedgerProductImportDto -> salesLedgerProductImportDto.getSalesContractNo().equals(salesLedger.getSalesContractNo())) |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(salesLedgerProductImportDtos)) |
| | | throw new RuntimeException("销售单号:" + salesLedgerImportDto.getSalesContractNo() + ",无对应产品数据!"); |
| | | salesLedger.setContractAmount(salesLedgerProductImportDtos.stream() |
| | | .map(SalesLedgerProductImportDto::getTaxInclusiveTotalPrice) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | // 发货状态 |
| | | salesLedger.setDeliveryStatus(1); |
| | | salesLedgerMapper.insert(salesLedger); |
| | | salesLedgerProduct.setActualPieceArea(actualPieceArea); |
| | | salesLedgerProduct.setActualTotalArea(actualPieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP)); |
| | | |
| | | for (SalesLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { |
| | | SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct); |
| | | salesLedgerProduct.setFloorCode(salesLedgerProductImportDto.getFloorNo()); |
| | | salesLedgerProduct.setProcessRequirement(salesLedgerProductImportDto.getProcessingRequirements()); |
| | | salesLedgerProduct.setRemark(salesLedgerProductImportDto.getRemarks()); |
| | | salesLedgerProduct.setSalesLedgerId(salesLedger.getId()); |
| | | salesLedgerProduct.setType(1); |
| | | // 计算不含税总价 |
| | | salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP)); |
| | | salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxExclusiveTotalPrice()); |
| | | list.stream() |
| | | .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel())) |
| | | .findFirst() |
| | | .ifPresent(map -> { |
| | | salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString())); |
| | | salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString())); |
| | | }); |
| | | salesLedgerProduct.setRegister(loginUser.getNickName()); |
| | | salesLedgerProduct.setRegisterDate(LocalDateTime.now()); |
| | | salesLedgerProduct.setApproveStatus(0); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | BigDecimal settlePieceArea = salesLedgerProduct.getSettlePieceArea() == null ? actualPieceArea : salesLedgerProduct.getSettlePieceArea(); |
| | | salesLedgerProduct.setSettlePieceArea(settlePieceArea); |
| | | salesLedgerProduct.setSettleTotalArea(settlePieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP)); |
| | | |
| | | // 处理额外加工信息 |
| | | String extraProcessing = salesLedgerProductImportDto.getExtraProcessing(); |
| | | if (StringUtils.hasText(extraProcessing)) { |
| | | List<SalesLedgerProductProcess> processList = new ArrayList<>(); |
| | | // 中英文分号 |
| | | String[] items = extraProcessing.split("[;;]"); |
| | | for (String item : items) { |
| | | if (StringUtils.hasText(item)) { |
| | | String[] parts = item.split("[-—~~]"); |
| | | if (parts.length >= 2) { |
| | | String processName = parts[0].trim(); |
| | | String qtyStr = parts[1].trim(); |
| | | try { |
| | | BigDecimal quantity = new BigDecimal(qtyStr); |
| | | SalesLedgerProductProcess process = salesLedgerProductProcessService.getOne( |
| | | new LambdaQueryWrapper<SalesLedgerProductProcess>() |
| | | .eq(SalesLedgerProductProcess::getProcessName, processName) |
| | | .last("LIMIT 1") |
| | | ); |
| | | if (process != null) { |
| | | SalesLedgerProductProcess p = new SalesLedgerProductProcess(); |
| | | p.setId(process.getId()); |
| | | p.setQuantity(quantity.intValue()); |
| | | processList.add(p); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("解析额外加工数量失败: {}", qtyStr); |
| | | BigDecimal perimeter = BigDecimal.ZERO; |
| | | if (width.compareTo(BigDecimal.ZERO) > 0 && height.compareTo(BigDecimal.ZERO) > 0) { |
| | | perimeter = width.add(height).multiply(new BigDecimal("2")).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP); |
| | | } |
| | | salesLedgerProduct.setPerimeter(perimeter); |
| | | |
| | | BigDecimal extraProcessAmountPerPiece = BigDecimal.ZERO; |
| | | list.stream().filter(Objects::nonNull).filter(map -> Objects.equals(Objects.toString(map.get("productName"), null), salesLedgerProduct.getProductCategory()) && Objects.equals(Objects.toString(map.get("model"), null), salesLedgerProduct.getSpecificationModel())).findFirst().ifPresent(map -> { |
| | | salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString())); |
| | | salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString())); |
| | | }); |
| | | salesLedgerProduct.setRegister(loginUser.getNickName()); |
| | | salesLedgerProduct.setRegisterDate(LocalDateTime.now()); |
| | | salesLedgerProduct.setApproveStatus(0); |
| | | salesLedgerProduct.setProductStockStatus(0); |
| | | |
| | | // 处理额外加工信息 |
| | | String extraProcessing = salesLedgerProductImportDto.getExtraProcessing(); |
| | | List<SalesLedgerProductProcess> processList = new ArrayList<>(); |
| | | if (StringUtils.hasText(extraProcessing)) { |
| | | // 中英文分号 |
| | | String[] items = extraProcessing.split("[;;]"); |
| | | for (String item : items) { |
| | | if (StringUtils.hasText(item)) { |
| | | String[] parts = item.split("[-—~~]"); |
| | | if (parts.length >= 2) { |
| | | String processName = parts[0].trim(); |
| | | String qtyStr = parts[1].trim(); |
| | | try { |
| | | BigDecimal processQty = new BigDecimal(qtyStr); |
| | | SalesLedgerProductProcess process = salesLedgerProductProcessService.getOne(new LambdaQueryWrapper<SalesLedgerProductProcess>().eq(SalesLedgerProductProcess::getProcessName, processName).last("LIMIT 1")); |
| | | if (process != null) { |
| | | SalesLedgerProductProcess p = new SalesLedgerProductProcess(); |
| | | p.setId(process.getId()); |
| | | p.setQuantity(processQty.intValue()); |
| | | processList.add(p); |
| | | extraProcessAmountPerPiece = extraProcessAmountPerPiece.add(defaultDecimal(process.getUnitPrice()).multiply(processQty)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("解析额外加工数量失败: {}", qtyStr); |
| | | } |
| | | } |
| | | } |
| | | if (!processList.isEmpty()) { |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(processList, salesLedgerProduct.getId()); |
| | | } |
| | | } |
| | | |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | |
| | | return AjaxResult.success("导入成功"); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | // 含税总价 = 单价 * 结算面积 * 数量 + 额外加工金额 * 数量 |
| | | BigDecimal taxInclusiveTotalPrice = unitPrice.multiply(settlePieceArea).multiply(quantity).add(extraProcessAmountPerPiece.multiply(quantity)).setScale(2, RoundingMode.HALF_UP); |
| | | salesLedgerProduct.setTaxInclusiveTotalPrice(taxInclusiveTotalPrice); |
| | | assertPositive(taxInclusiveTotalPrice, "含税总价", locate); |
| | | |
| | | // 税率允许为空,空值按0处理 |
| | | BigDecimal taxDivisor = BigDecimal.ONE.add(taxRate.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP)); |
| | | salesLedgerProduct.setTaxExclusiveTotalPrice(taxInclusiveTotalPrice.divide(taxDivisor, 2, RoundingMode.HALF_UP)); |
| | | salesLedgerProduct.setNoInvoiceNum(quantity); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxExclusiveTotalPrice()); |
| | | salesLedgerProduct.setPendingInvoiceTotal(taxInclusiveTotalPrice); |
| | | salesLedgerProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | if (!processList.isEmpty()) { |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(processList, salesLedgerProduct.getId()); |
| | | } |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | contractAmount = contractAmount.add(taxInclusiveTotalPrice); |
| | | } |
| | | salesLedger.setContractAmount(contractAmount); |
| | | salesLedgerMapper.updateById(salesLedger); |
| | | } |
| | | return AjaxResult.success("导入失败"); |
| | | } |
| | | |
| | | private BigDecimal defaultDecimal(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | private void assertPositive(BigDecimal value, String fieldName, String locate) { |
| | | if (value == null || value.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("导入失败:" + locate + "【" + fieldName + "】必须大于0"); |
| | | } |
| | | } |
| | | |
| | | private void assertNonNegative(BigDecimal value, String fieldName, String locate) { |
| | | if (value != null && value.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("导入失败:" + locate + "【" + fieldName + "】不能为负数"); |
| | | } |
| | | } |
| | | |
| | | private String buildImportLocate(String salesContractNo, SalesLedgerProductImportDto dto) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("销售单号[").append(salesContractNo == null ? "" : salesContractNo).append("]"); |
| | | if (dto != null) { |
| | | if (StringUtils.hasText(dto.getProductCategory())) { |
| | | sb.append(" 产品大类[").append(dto.getProductCategory()).append("]"); |
| | | } |
| | | if (StringUtils.hasText(dto.getSpecificationModel())) { |
| | | sb.append(" 规格型号[").append(dto.getSpecificationModel()).append("]"); |
| | | } |
| | | if (StringUtils.hasText(dto.getFloorNo())) { |
| | | sb.append(" 楼层编号[").append(dto.getFloorNo()).append("]"); |
| | | } |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | @Override |
| | | public List<LossProductModelDto> getSalesLedgerWithProductsLoss(Long salesLedgerId) { |
| | | |
| | | |
| | | List<LossProductModelDto> lossProductModelDtos = salesLedgerProductMapper.selectProductBomStructure(salesLedgerId); |
| | | |
| | | |
| | | return lossProductModelDtos; |
| | | } |
| | | |
| | |
| | | product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); |
| | | product.setRegisterDate(LocalDateTime.now()); |
| | | // 发货信息 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, product.getId()) |
| | | .orderByDesc(ShippingInfo::getCreateTime) |
| | | .last("limit 1")); |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerProductId, product.getId()).orderByDesc(ShippingInfo::getCreateTime).last("limit 1")); |
| | | product.setShippingCarNumber(shippingInfo.getShippingCarNumber()); |
| | | product.setShippingDate(shippingInfo.getShippingDate()); |
| | | if (shippingInfo != null) { |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int deleteSalesLedgerByIds(Long[] ids) { |
| | | List<Long> idList = Arrays.stream(ids) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | List<Long> idList = Arrays.stream(ids).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(idList)) { |
| | | return 0; |
| | | } |
| | | // 删除销售管理数据 |
| | | LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList) |
| | | .select(SalesLedgerProduct::getId); |
| | | queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList).select(SalesLedgerProduct::getId); |
| | | |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(queryWrapper); |
| | | List<Long> productIds = products.stream() |
| | | .map(SalesLedgerProduct::getId) |
| | | .collect(Collectors.toList()); |
| | | List<Long> productIds = products.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList()); |
| | | //删除生产数据 |
| | | salesLedgerProductServiceImpl.deleteProductionData(productIds); |
| | | |
| | |
| | | receiptPaymentMapper.delete(wrapperTree); |
| | | } |
| | | // 删除发货台账记录 |
| | | List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>() |
| | | .in(ShippingInfo::getSalesLedgerId, idList)); |
| | | List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>().in(ShippingInfo::getSalesLedgerId, idList)); |
| | | if (CollectionUtils.isNotEmpty(shippingInfos)) { |
| | | shippingInfoServiceImpl.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList())); |
| | | } |
| | | // 删除关联的入库/出库记录(走服务层删除,触发库存数量回退) |
| | | List<Long> stockInRecordIds = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>().in(StockInRecord::getSalesLedgerId, idList).select(StockInRecord::getId)).stream().map(StockInRecord::getId).collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(stockInRecordIds)) { |
| | | stockInRecordService.batchDelete(stockInRecordIds); |
| | | } |
| | | List<Long> stockOutRecordIds = stockOutRecordMapper.selectList(new LambdaQueryWrapper<StockOutRecord>().in(StockOutRecord::getSalesLedgerId, idList).select(StockOutRecord::getId)).stream().map(StockOutRecord::getId).collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(stockOutRecordIds)) { |
| | | stockOutRecordService.batchDelete(stockOutRecordIds); |
| | | } |
| | | // 删除附件表 |
| | | commonFileService.deleteByBusinessIds(idList, FileNameType.SALE.getValue()); |
| | |
| | | List<SalesLedgerProduct> productList = salesLedgerDto.getProductData(); |
| | | if (productList != null && !productList.isEmpty()) { |
| | | handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType())); |
| | | updateMainContractAmount( |
| | | salesLedger.getId(), |
| | | productList, |
| | | SalesLedgerProduct::getTaxInclusiveTotalPrice, |
| | | salesLedgerMapper, |
| | | SalesLedger.class |
| | | ); |
| | | updateMainContractAmount(salesLedger.getId(), productList, SalesLedgerProduct::getTaxInclusiveTotalPrice, salesLedgerMapper, SalesLedger.class); |
| | | } |
| | | |
| | | // 5. 迁移临时文件到正式目录 |
| | |
| | | // 构建正式文件名(包含业务ID和时间戳,避免冲突) |
| | | String originalFilename = tempFile.getOriginalName(); |
| | | String fileExtension = FilenameUtils.getExtension(originalFilename); |
| | | String formalFilename = businessId + "_" + |
| | | System.currentTimeMillis() + "_" + |
| | | UUID.randomUUID().toString().substring(0, 8) + |
| | | (StringUtils.hasText(fileExtension) ? "." + fileExtension : ""); |
| | | String formalFilename = businessId + "_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + (StringUtils.hasText(fileExtension) ? "." + fileExtension : ""); |
| | | |
| | | Path formalFilePath = formalDirPath.resolve(formalFilename); |
| | | |
| | |
| | | @Override |
| | | public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) { |
| | | // 按ID分组,区分新增和更新的记录 |
| | | Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream() |
| | | .peek(p -> p.setSalesLedgerId(salesLedgerId)) |
| | | .collect(Collectors.partitioningBy(p -> p.getId() != null)); |
| | | Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream().peek(p -> p.setSalesLedgerId(salesLedgerId)).collect(Collectors.partitioningBy(p -> p.getId() != null)); |
| | | |
| | | List<SalesLedgerProduct> updateList = partitionedProducts.get(true); |
| | | List<SalesLedgerProduct> insertList = partitionedProducts.get(false); |
| | |
| | | if (!updateList.isEmpty()) { |
| | | for (SalesLedgerProduct product : updateList) { |
| | | product.setType(type.getCode()); |
| | | SalesLedgerProduct db = salesLedgerProductMapper.selectById(product.getId()); |
| | | if (db != null) { |
| | | BigDecimal stockedQty = product.getStockedQuantity() != null ? product.getStockedQuantity() : db.getStockedQuantity(); |
| | | BigDecimal orderQty = product.getQuantity() != null ? product.getQuantity() : db.getQuantity(); |
| | | product.setStockedQuantity(stockedQty); |
| | | product.setProductStockStatus(calculateProductStockStatus(stockedQty, orderQty)); |
| | | } else { |
| | | product.setProductStockStatus(0); |
| | | } |
| | | product.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(product); |
| | | // 清空销售产品绑定的加工 |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(product.getSalesProductProcessList(), product.getId()); |
| | |
| | | salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | BigDecimal stockedQty = salesLedgerProduct.getStockedQuantity(); |
| | | BigDecimal orderQty = salesLedgerProduct.getQuantity(); |
| | | salesLedgerProduct.setProductStockStatus(calculateProductStockStatus(stockedQty, orderQty)); |
| | | salesLedgerProduct.fillRemainingQuantity(); |
| | | ProductModel productModel = productModelMapper.selectById(salesLedgerProduct.getProductModelId()); |
| | | if (productModel == null) { |
| | | throw new ServiceException("新增销售台账失败,销售产品不存在"); |
| | | } |
| | | salesLedgerProduct.setUnit(productModel.getUnit()); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | // 绑定产品额外加工 |
| | | // 清空销售产品绑定的加工 |
| | |
| | | // salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | refreshSalesLedgerStockStatus(salesLedgerId); |
| | | } |
| | | |
| | | private int calculateProductStockStatus(BigDecimal stockedQty, BigDecimal orderQty) { |
| | | BigDecimal stocked = stockedQty == null ? BigDecimal.ZERO : stockedQty; |
| | | BigDecimal order = orderQty == null ? BigDecimal.ZERO : orderQty; |
| | | if (stocked.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return 0; |
| | | } |
| | | if (order.compareTo(BigDecimal.ZERO) > 0 && stocked.compareTo(order) < 0) { |
| | | return 1; |
| | | } |
| | | return 2; |
| | | } |
| | | |
| | | private void refreshSalesLedgerStockStatus(Long salesLedgerId) { |
| | | if (salesLedgerId == null) return; |
| | | SalesLedger ledger = baseMapper.selectById(salesLedgerId); |
| | | if (ledger == null) return; |
| | | List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode())); |
| | | if (CollectionUtils.isEmpty(allProducts)) { |
| | | ledger.setStockStatus(0); |
| | | baseMapper.updateById(ledger); |
| | | return; |
| | | } |
| | | boolean anyInbound = allProducts.stream().anyMatch(p -> { |
| | | BigDecimal sq = p.getStockedQuantity(); |
| | | return sq != null && sq.compareTo(BigDecimal.ZERO) > 0; |
| | | }); |
| | | boolean allFull = allProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2)); |
| | | ledger.setStockStatus(allFull ? 2 : (anyInbound ? 1 : 0)); |
| | | baseMapper.updateById(ledger); |
| | | } |
| | | |
| | | private SalesLedger convertToEntity(SalesLedgerDto dto) { |
| | |
| | | } finally { |
| | | // 3. 释放锁 |
| | | String luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end"; |
| | | redisTemplate.execute( |
| | | new DefaultRedisScript<>(luaScript, Long.class), |
| | | Collections.singletonList(lockKey), |
| | | lockValue |
| | | ); |
| | | redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class), Collections.singletonList(lockKey), lockValue); |
| | | } |
| | | } |
| | | |
| | |
| | | dto.setOrderProcessRequirement(salesLedger.getRemarks()); |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | BigDecimal totalQuantity = BigDecimal.ZERO; |
| | | BigDecimal totalArea = BigDecimal.ZERO; |
| | |
| | | SalesProcessCardDto.ProcessCardItemDto itemDto = new SalesProcessCardDto.ProcessCardItemDto(); |
| | | itemDto.setFloorCode(p.getFloorCode()); |
| | | // 组装产品描述:大类 + (规格) |
| | | String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + |
| | | (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : ""); |
| | | String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : ""); |
| | | itemDto.setProductDescription(desc.trim()); |
| | | itemDto.setWidth(p.getWidth()); |
| | | itemDto.setHeight(p.getHeight()); |
| | |
| | | dto.setTotalArea(totalArea.setScale(2, RoundingMode.HALF_UP)); |
| | | |
| | | // 工艺路线 |
| | | List<SalesLedgerProcessRoute> salesLedgerProcessRoutes = salesLedgerProcessRouteService.list( |
| | | new LambdaQueryWrapper<SalesLedgerProcessRoute>() |
| | | .eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedgerId) |
| | | .orderByAsc(SalesLedgerProcessRoute::getDragSort)); |
| | | List<SalesLedgerProcessRoute> salesLedgerProcessRoutes = salesLedgerProcessRouteService.list(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedgerId).orderByAsc(SalesLedgerProcessRoute::getDragSort)); |
| | | |
| | | List<SalesProcessCardDto.ProcessNodeDto> nodeDtos = new ArrayList<>(); |
| | | |
| | | if (CollectionUtils.isEmpty(salesLedgerProcessRoutes)) { |
| | | // 无自定义路线,取默认路线 |
| | | ProcessRoute defaultRoute = processRouteMapper.selectOne( |
| | | new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("LIMIT 1")); |
| | | if (defaultRoute != null) { |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList( |
| | | new LambdaQueryWrapper<ProcessRouteItem>() |
| | | .eq(ProcessRouteItem::getRouteId, defaultRoute.getId()) |
| | | .orderByAsc(ProcessRouteItem::getDragSort)); |
| | | // 无自定义路线:先查询默认工艺路线;若无默认,获取创建时间最近的一条 |
| | | ProcessRoute fallbackRoute = processRouteMapper.selectOne(new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("LIMIT 1")); |
| | | if (fallbackRoute == null) { |
| | | fallbackRoute = processRouteMapper.selectOne(new LambdaQueryWrapper<ProcessRoute>().orderByDesc(ProcessRoute::getCreateTime).last("LIMIT 1")); |
| | | } |
| | | if (fallbackRoute != null) { |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, fallbackRoute.getId()).orderByAsc(ProcessRouteItem::getDragSort)); |
| | | for (ProcessRouteItem i : routeItems) { |
| | | SalesProcessCardDto.ProcessNodeDto node = new SalesProcessCardDto.ProcessNodeDto(); |
| | | node.setProcessRouteItemId(i.getId()); |
| | |
| | | } |
| | | } else { |
| | | // 使用自定义路线绑定的节点 |
| | | List<Long> itemIds = salesLedgerProcessRoutes.stream() |
| | | .map(SalesLedgerProcessRoute::getProcessRouteItemId) |
| | | .collect(Collectors.toList()); |
| | | List<Long> itemIds = salesLedgerProcessRoutes.stream().map(SalesLedgerProcessRoute::getProcessRouteItemId).collect(Collectors.toList()); |
| | | List<ProcessRouteItem> rawItems = processRouteItemMapper.selectBatchIds(itemIds); |
| | | Map<Long, ProcessRouteItem> itemMap = rawItems.stream() |
| | | .collect(Collectors.toMap(ProcessRouteItem::getId, i -> i, (a, b) -> a)); |
| | | Map<Long, ProcessRouteItem> itemMap = rawItems.stream().collect(Collectors.toMap(ProcessRouteItem::getId, i -> i, (a, b) -> a)); |
| | | |
| | | for (SalesLedgerProcessRoute r : salesLedgerProcessRoutes) { |
| | | ProcessRouteItem pi = itemMap.get(r.getProcessRouteItemId()); |
| | |
| | | |
| | | if (!nodeDtos.isEmpty()) { |
| | | // dragSort 进行升序排序 |
| | | nodeDtos.sort(Comparator.comparing( |
| | | SalesProcessCardDto.ProcessNodeDto::getDragSort, |
| | | Comparator.nullsLast(Comparator.naturalOrder()) |
| | | )); |
| | | nodeDtos.sort(Comparator.comparing(SalesProcessCardDto.ProcessNodeDto::getDragSort, Comparator.nullsLast(Comparator.naturalOrder()))); |
| | | // 重新生成排序后的路径名称列表 |
| | | List<String> sortedPathNames = nodeDtos.stream() |
| | | .map(SalesProcessCardDto.ProcessNodeDto::getProcessRouteItemName) |
| | | .collect(Collectors.toList()); |
| | | List<String> sortedPathNames = nodeDtos.stream().map(SalesProcessCardDto.ProcessNodeDto::getProcessRouteItemName).collect(Collectors.toList()); |
| | | // 拼接字符串 |
| | | dto.setProcessPathDisplay(String.join(" -> ", sortedPathNames)); |
| | | // 设置顶层节点的工艺路线 |
| | |
| | | dto.setPrintTime(LocalDateTime.now()); |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | SalesLedgerProduct firstProduct = products.get(0); |
| | |
| | | for (SalesLedgerProduct p : products) { |
| | | SalesOrdersDto.SalesOrderItemDto itemDto = new SalesOrdersDto.SalesOrderItemDto(); |
| | | itemDto.setFloorCode(p.getFloorCode()); |
| | | String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + |
| | | (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : ""); |
| | | String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : ""); |
| | | itemDto.setProductDescription(desc.trim()); |
| | | itemDto.setWidth(p.getWidth()); |
| | | itemDto.setHeight(p.getHeight()); |
| | |
| | | List<Long> productIds = products.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList()); |
| | | BigDecimal otherFeesTotal = BigDecimal.ZERO; |
| | | if (CollectionUtils.isNotEmpty(productIds)) { |
| | | List<SalesLedgerProductProcessBind> binds = salesLedgerProductProcessBindService.list( |
| | | new LambdaQueryWrapper<SalesLedgerProductProcessBind>().in(SalesLedgerProductProcessBind::getSalesLedgerProductId, productIds)); |
| | | List<SalesLedgerProductProcessBind> binds = salesLedgerProductProcessBindService.list(new LambdaQueryWrapper<SalesLedgerProductProcessBind>().in(SalesLedgerProductProcessBind::getSalesLedgerProductId, productIds)); |
| | | |
| | | if (CollectionUtils.isNotEmpty(binds)) { |
| | | Map<Integer, Integer> processQuantityMap = binds.stream() |
| | | .collect(Collectors.groupingBy(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, |
| | | Collectors.summingInt(b -> b.getQuantity() != null ? b.getQuantity() : 0))); |
| | | Map<Integer, Integer> processQuantityMap = binds.stream().collect(Collectors.groupingBy(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, Collectors.summingInt(b -> b.getQuantity() != null ? b.getQuantity() : 0))); |
| | | |
| | | List<Integer> processIds = new ArrayList<>(processQuantityMap.keySet()); |
| | | List<SalesLedgerProductProcess> processes = salesLedgerProductProcessService.listByIds(processIds); |
| | |
| | | // dto.setExternalOrderNo(ledgers.get(0).getCustomerContractNo()); |
| | | |
| | | // 查询所有产品 |
| | | List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds)); |
| | | List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds).eq(SalesLedgerProduct::getType, 1)); |
| | | |
| | | if (CollectionUtils.isNotEmpty(allProducts)) { |
| | | Map<Long, SalesLedger> ledgerMap = ledgers.stream() |
| | | .collect(Collectors.toMap(SalesLedger::getId, Function.identity())); |
| | | |
| | | Map<Long, List<SalesLedgerProduct>> groupedData = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct p : allProducts) { |
| | | groupedData.computeIfAbsent(p.getSalesLedgerId(), k -> new ArrayList<>()).add(p); |
| | | } |
| | | Map<Long, SalesLedger> ledgerMap = ledgers.stream().collect(Collectors.toMap(SalesLedger::getId, Function.identity())); |
| | | |
| | | List<SalesInvoicesDto.InvoiceOrderGroupDto> groups = new ArrayList<>(); |
| | | BigDecimal totalQty = BigDecimal.ZERO; |
| | | BigDecimal totalArea = BigDecimal.ZERO; |
| | | |
| | | for (Map.Entry<Long, List<SalesLedgerProduct>> ledgerEntry : groupedData.entrySet()) { |
| | | SalesLedger ledger = ledgerMap.get(ledgerEntry.getKey()); |
| | | String orderNo = ledger != null ? ledger.getSalesContractNo() : ""; |
| | | List<SalesLedgerProduct> products = ledgerEntry.getValue(); |
| | | Map<String, List<SalesLedgerProduct>> groupedData = new LinkedHashMap<>(); |
| | | Map<String, Set<String>> groupOrderNos = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct p : allProducts) { |
| | | String productCategory = StringUtils.defaultString(p.getProductCategory(), ""); |
| | | String specificationModel = StringUtils.defaultString(p.getSpecificationModel(), ""); |
| | | String groupKey = productCategory + "||" + specificationModel; |
| | | groupedData.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(p); |
| | | |
| | | SalesLedger ledger = ledgerMap.get(p.getSalesLedgerId()); |
| | | String orderNo = ledger != null ? StringUtils.defaultString(ledger.getSalesContractNo(), "") : ""; |
| | | if (StringUtils.isNotEmpty(orderNo)) { |
| | | groupOrderNos.computeIfAbsent(groupKey, k -> new LinkedHashSet<>()).add(orderNo); |
| | | } |
| | | } |
| | | |
| | | for (Map.Entry<String, List<SalesLedgerProduct>> productEntry : groupedData.entrySet()) { |
| | | String key = productEntry.getKey(); |
| | | String[] parts = key.split("\\|\\|", -1); |
| | | String productName = parts.length > 0 ? parts[0] : ""; |
| | | String specificationModel = parts.length > 1 ? parts[1] : ""; |
| | | List<SalesLedgerProduct> products = productEntry.getValue(); |
| | | |
| | | SalesInvoicesDto.InvoiceOrderGroupDto group = new SalesInvoicesDto.InvoiceOrderGroupDto(); |
| | | group.setSalesContractNo(orderNo); |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | group.setProductName(products.get(0).getProductCategory()); |
| | | } |
| | | Set<String> orderNos = groupOrderNos.getOrDefault(key, Collections.emptySet()); |
| | | group.setSalesContractNo(String.join(",", orderNos)); |
| | | group.setProductName(productName); |
| | | group.setSpecificationModel(specificationModel); |
| | | |
| | | List<SalesInvoicesDto.InvoiceItemDto> itemDtos = new ArrayList<>(); |
| | | Map<String, SalesInvoicesDto.InvoiceItemDto> mergedItems = new LinkedHashMap<>(); |
| | | BigDecimal groupQty = BigDecimal.ZERO; |
| | | BigDecimal groupArea = BigDecimal.ZERO; |
| | | |
| | | for (SalesLedgerProduct p : products) { |
| | | SalesInvoicesDto.InvoiceItemDto item = new SalesInvoicesDto.InvoiceItemDto(); |
| | | item.setFloorCode(p.getFloorCode()); |
| | | item.setWidthHeight((p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + |
| | | " * " + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0")); |
| | | item.setQuantity(p.getQuantity()); |
| | | String widthHeight = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + " * " + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0"); |
| | | String floorCode = StringUtils.defaultString(p.getFloorCode(), ""); |
| | | String remark = StringUtils.defaultString(p.getRemark(), ""); |
| | | String processReq = StringUtils.defaultString(p.getProcessRequirement(), ""); |
| | | String itemKey = floorCode + "||" + widthHeight + "||" + remark + "||" + processReq; |
| | | |
| | | BigDecimal qty = p.getQuantity() != null ? p.getQuantity() : BigDecimal.ZERO; |
| | | |
| | | // 面积 |
| | | BigDecimal area = p.getSettleTotalArea() != null ? p.getSettleTotalArea() : p.getActualTotalArea(); |
| | | if (area == null && p.getWidth() != null && p.getHeight() != null && p.getQuantity() != null) { |
| | | area = p.getWidth().multiply(p.getHeight()).multiply(p.getQuantity()).divide(new BigDecimal(1000000), 2, RoundingMode.HALF_UP); |
| | | } |
| | | item.setArea(area); |
| | | item.setRemark(p.getRemark()); |
| | | item.setProcessRequirement(p.getProcessRequirement()); |
| | | area = area != null ? area : BigDecimal.ZERO; |
| | | |
| | | itemDtos.add(item); |
| | | groupQty = groupQty.add(p.getQuantity() != null ? p.getQuantity() : BigDecimal.ZERO); |
| | | groupArea = groupArea.add(area != null ? area : BigDecimal.ZERO); |
| | | SalesInvoicesDto.InvoiceItemDto item = mergedItems.get(itemKey); |
| | | if (item == null) { |
| | | item = new SalesInvoicesDto.InvoiceItemDto(); |
| | | item.setFloorCode(floorCode); |
| | | item.setWidthHeight(widthHeight); |
| | | item.setSpecificationModel(p.getSpecificationModel()); |
| | | item.setQuantity(qty); |
| | | item.setArea(area); |
| | | item.setRemark(remark); |
| | | item.setProcessRequirement(processReq); |
| | | mergedItems.put(itemKey, item); |
| | | } else { |
| | | item.setQuantity((item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO).add(qty)); |
| | | item.setArea((item.getArea() != null ? item.getArea() : BigDecimal.ZERO).add(area)); |
| | | } |
| | | |
| | | groupQty = groupQty.add(qty); |
| | | groupArea = groupArea.add(area); |
| | | } |
| | | |
| | | group.setItems(itemDtos); |
| | | group.setItems(new ArrayList<>(mergedItems.values())); |
| | | group.setGroupTotalQuantity(groupQty); |
| | | group.setGroupTotalArea(groupArea.setScale(2, RoundingMode.HALF_UP)); |
| | | groups.add(group); |
| | |
| | | } |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | // 查询客户地址 |
| | | String fullAddress = ""; |
| | |
| | | SalesLabelDto dto = new SalesLabelDto(); |
| | | dto.setCustomerName(salesLedger.getCustomerName()); |
| | | dto.setSalesContractNo(salesLedger.getSalesContractNo()); |
| | | dto.setProductName(p.getProductCategory()); |
| | | dto.setProductName(p.getSpecificationModel()); |
| | | |
| | | // 宽*高=数量 |
| | | String specification = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + "*" + |
| | | (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0") + "=" + |
| | | (p.getQuantity() != null ? p.getQuantity().stripTrailingZeros().toPlainString() : "0"); |
| | | String specification = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + "*" + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0") + "=" + (p.getQuantity() != null ? p.getQuantity().stripTrailingZeros().toPlainString() : "0"); |
| | | dto.setSpecification(specification); |
| | | |
| | | // 客户地址 + 楼层编号 |
| | |
| | | return next; |
| | | } |
| | | |
| | | public <T, S> void updateMainContractAmount( |
| | | Long mainId, |
| | | List<T> subList, |
| | | Function<T, BigDecimal> amountGetter, |
| | | BaseMapper<S> mainMapper, |
| | | Class<S> mainEntityClass) { |
| | | public <T, S> void updateMainContractAmount(Long mainId, List<T> subList, Function<T, BigDecimal> amountGetter, BaseMapper<S> mainMapper, Class<S> mainEntityClass) { |
| | | |
| | | if (mainId == null || subList == null || subList.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | // 计算子表金额总和 |
| | | BigDecimal totalAmount = subList.stream() |
| | | .map(amountGetter) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal totalAmount = subList.stream().map(amountGetter).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | // 构造主表更新对象 |
| | | try { |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void salesStock(SalesLedger salesLedger) { |
| | | if (salesLedger == null || salesLedger.getId() == null) { |
| | | public void salesStock(SalesProductStockDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new NullPointerException("入库失败,请选择需要入库的销售订单"); |
| | | } |
| | | // 查询销售订单是否存在 |
| | | SalesLedger ledger = baseMapper.selectById(salesLedger.getId()); |
| | | SalesLedger ledger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (ledger == null) { |
| | | throw new ServiceException("入库失败,销售订单不存在"); |
| | | } |
| | | if (ledger.getStockStatus() == null) { |
| | | throw new ServiceException("入库失败,销售订单入库状态异常"); |
| | | } |
| | | if (ledger.getStockStatus() == 1) { |
| | | if (ledger.getStockStatus() == 3) { |
| | | throw new ServiceException("入库失败,该销售订单正在入库审批中,请勿重复提交"); |
| | | } |
| | | if (ledger.getStockStatus() == 2) { |
| | | throw new ServiceException("入库失败,该销售订单已入库,请勿重复入库"); |
| | | } |
| | | List<Long> products = dto.getSalesLedgerProducts(); |
| | | if (products == null || products.isEmpty()) { |
| | | throw new ServiceException("入库失败,入库产品不能为空"); |
| | | } |
| | | // 查询销售订单的产品 |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId())); |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, products)); |
| | | if (salesLedgerProducts == null || salesLedgerProducts.isEmpty()) { |
| | | throw new ServiceException("入库失败,未查询到该销售订单的销售产品"); |
| | | } |
| | | String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), ledger.getId(), INBOUND_BIZ_TYPE_WEB); |
| | | if (StringUtils.isEmpty(approveUserIds)) { |
| | | throw new ServiceException("入库失败,请选择审批人"); |
| | | } |
| | | |
| | | String productIds = products.stream().map(String::valueOf).collect(Collectors.joining(",")); |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | ApproveProcessVO approveProcessVO = new ApproveProcessVO(); |
| | | approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode()); |
| | | approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId()); |
| | | approveProcessVO.setApproveReason("入库审批:" + ledger.getSalesContractNo()); |
| | | approveProcessVO.setApproveRemark("salesStock:" + ledger.getId() + ":" + productIds); |
| | | approveProcessVO.setApproveUserIds(approveUserIds); |
| | | approveProcessVO.setApproveUser(loginUser.getUserId()); |
| | | approveProcessVO.setApproveTime(LocalDate.now().toString()); |
| | | try { |
| | | approveProcessService.addApprove(approveProcessVO); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("入库审批发起失败:" + e.getMessage()); |
| | | } |
| | | // 审批中 |
| | | ledger.setStockStatus(3); |
| | | baseMapper.updateById(ledger); |
| | | } |
| | | |
| | | @Override |
| | | public void executeSalesStockApproved(Long salesLedgerId, List<Long> products) { |
| | | SalesProductStockDto dto = new SalesProductStockDto(); |
| | | dto.setSalesLedgerId(salesLedgerId); |
| | | dto.setSalesLedgerProducts(products); |
| | | |
| | | SalesLedger ledger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (ledger == null) { |
| | | throw new ServiceException("入库失败,销售订单不存在"); |
| | | } |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, products)); |
| | | for (SalesLedgerProduct product : salesLedgerProducts) { |
| | | if (!Objects.equals(product.getSalesLedgerId(), ledger.getId())) { |
| | | throw new ServiceException("入库失败,存在不属于当前销售订单的产品"); |
| | | } |
| | | if (product.getProductModelId() == null) { |
| | | continue; |
| | | } |
| | | StockInventoryDto dto = new StockInventoryDto(); |
| | | dto.setRecordId(product.getId()); |
| | | dto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode()); |
| | | dto.setQualitity(product.getQuantity()); |
| | | dto.setProductModelId(product.getProductModelId()); |
| | | stockInventoryService.addstockInventory(dto); |
| | | BigDecimal orderQty = product.getQuantity() == null ? BigDecimal.ZERO : product.getQuantity(); |
| | | BigDecimal oldStocked = product.getStockedQuantity() == null ? BigDecimal.ZERO : product.getStockedQuantity(); |
| | | BigDecimal inboundQty = orderQty.subtract(oldStocked); |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) < 0) { |
| | | inboundQty = BigDecimal.ZERO; |
| | | } |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordId(product.getId()); |
| | | stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode()); |
| | | stockInventoryDto.setQualitity(inboundQty); |
| | | stockInventoryDto.setProductModelId(product.getProductModelId()); |
| | | stockInventoryDto.setSalesLedgerId(ledger.getId()); |
| | | stockInventoryDto.setSalesLedgerProductId(product.getId()); |
| | | stockInventoryService.addstockInventory(stockInventoryDto); |
| | | |
| | | BigDecimal newStocked = oldStocked.add(inboundQty); |
| | | int lineStockStatus; |
| | | if (newStocked.compareTo(BigDecimal.ZERO) <= 0) { |
| | | lineStockStatus = 0; |
| | | } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) { |
| | | lineStockStatus = 1; |
| | | } else { |
| | | lineStockStatus = 2; |
| | | } |
| | | product.setStockedQuantity(newStocked); |
| | | product.setProductStockStatus(lineStockStatus); |
| | | product.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(product); |
| | | } |
| | | // 按销售订单产品入库情况更新主单入库状态:1-部分入库,2-已入库 |
| | | List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId())); |
| | | boolean hasStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().anyMatch(item -> { |
| | | BigDecimal sq = item.getStockedQuantity(); |
| | | return sq != null && sq.compareTo(BigDecimal.ZERO) > 0; |
| | | }); |
| | | boolean allStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().allMatch(item -> { |
| | | BigDecimal orderQty = item.getQuantity() == null ? BigDecimal.ZERO : item.getQuantity(); |
| | | BigDecimal stockedQty = item.getStockedQuantity() == null ? BigDecimal.ZERO : item.getStockedQuantity(); |
| | | return orderQty.compareTo(BigDecimal.ZERO) <= 0 || stockedQty.compareTo(orderQty) >= 0; |
| | | }); |
| | | ledger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0)); |
| | | baseMapper.updateById(ledger); |
| | | } |
| | | |
| | | @Override |
| | | public List<Customer> shippedCustomers() { |
| | | List<SalesLedger> ledgers = list(Wrappers.<SalesLedger>lambdaQuery().eq(SalesLedger::getDeliveryStatus, 5).isNotNull(SalesLedger::getCustomerId).select(SalesLedger::getCustomerId)); |
| | | if (CollectionUtils.isEmpty(ledgers)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Set<Long> customerIds = ledgers.stream().map(SalesLedger::getCustomerId).collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | return customerMapper.selectList(Wrappers.<Customer>lambdaQuery().in(Customer::getId, customerIds).orderByAsc(Customer::getCustomerName)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scanInbound(SalesScanInboundDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new ServiceException("销售订单入库失败,入库数据不能为空"); |
| | | } |
| | | |
| | | SalesLedger salesLedger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("入库失败,销售订单不存在"); |
| | | } |
| | | if (salesLedger.getStockStatus() == null) { |
| | | throw new ServiceException("入库失败,销售订单状态异常"); |
| | | } |
| | | if (salesLedger.getStockStatus() == 2) { |
| | | throw new ServiceException("入库失败,该销售订单已全部入库"); |
| | | } |
| | | if (salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("入库失败,该销售订单已发货"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("销售订单入库失败,入库产品不能为空"); |
| | | } |
| | | // 本次入库数量可以大于订单数量,但不能为负 |
| | | Map<Long, BigDecimal> inboundQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct inbound : dto.getSalesLedgerProductList()) { |
| | | if (inbound == null || inbound.getId() == null) { |
| | | throw new ServiceException("入库失败,销售产品信息不完整"); |
| | | } |
| | | BigDecimal inboundQty = inbound.getStockedQuantity(); |
| | | if (inboundQty == null) { |
| | | throw new ServiceException("入库失败,入库数量不能为空"); |
| | | } |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("入库失败,入库数量不能为负数"); |
| | | } |
| | | inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add); |
| | | } |
| | | List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet())); |
| | | if (CollectionUtils.isEmpty(selectedProducts)) { |
| | | throw new ServiceException("入库失败,未查询到入库产品"); |
| | | } |
| | | if (selectedProducts.size() != inboundQtyByLineId.size()) { |
| | | throw new ServiceException("入库失败,部分产品不存在"); |
| | | } |
| | | for (SalesLedgerProduct selectedProduct : selectedProducts) { |
| | | if (!Objects.equals(selectedProduct.getSalesLedgerId(), salesLedger.getId())) { |
| | | throw new ServiceException("入库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (!Objects.equals(selectedProduct.getType(), SaleEnum.SALE.getCode())) { |
| | | throw new ServiceException("入库失败,仅支持销售订单产品行"); |
| | | } |
| | | if (selectedProduct.getProductModelId() == null) { |
| | | throw new ServiceException("入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | } |
| | | String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_QUALIFIED); |
| | | if (StringUtils.isEmpty(approveUserIds)) { |
| | | throw new ServiceException("入库失败,请选择审批人"); |
| | | } |
| | | String lines = inboundQtyByLineId.entrySet().stream().map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString()).collect(Collectors.joining(",")); |
| | | String reason = "销售扫码合格入库审批:" + salesLedger.getSalesContractNo(); |
| | | String remark = "scanQualified:" + salesLedger.getId() + ":" + lines; |
| | | ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveRemark, remark).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1")); |
| | | if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) { |
| | | throw new ServiceException("入库失败,该申请已提交审批"); |
| | | } |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | ApproveProcessVO approveProcessVO = new ApproveProcessVO(); |
| | | approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode()); |
| | | approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId()); |
| | | approveProcessVO.setApproveReason(reason); |
| | | approveProcessVO.setApproveRemark(remark); |
| | | approveProcessVO.setApproveUserIds(approveUserIds); |
| | | approveProcessVO.setApproveUser(loginUser.getUserId()); |
| | | approveProcessVO.setApproveTime(LocalDate.now().toString()); |
| | | try { |
| | | approveProcessService.addApprove(approveProcessVO); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("入库审批发起失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void executeSalesScanInboundApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId) { |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerId); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("入库失败,销售订单不存在"); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal inboundThisLine = entry.getValue(); |
| | | if (inboundThisLine == null || inboundThisLine.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId); |
| | | if (dbProduct == null) { |
| | | throw new ServiceException("入库失败,销售产品不存在"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getSalesLedgerId(), ledgerId)) { |
| | | throw new ServiceException("入库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getType(), SaleEnum.SALE.getCode())) { |
| | | throw new ServiceException("入库失败,仅支持销售订单产品行"); |
| | | } |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | BigDecimal oldStocked = dbProduct.getStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getStockedQuantity(); |
| | | BigDecimal newStocked = oldStocked.add(inboundThisLine); |
| | | |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordId(dbProduct.getId()); |
| | | stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_SCAN_STOCK_IN.getCode()); |
| | | stockInventoryDto.setQualitity(inboundThisLine); |
| | | stockInventoryDto.setProductModelId(dbProduct.getProductModelId()); |
| | | stockInventoryDto.setSalesLedgerId(ledgerId); |
| | | stockInventoryDto.setSalesLedgerProductId(dbProduct.getId()); |
| | | stockInventoryService.addstockInventory(stockInventoryDto); |
| | | |
| | | BigDecimal orderQty = dbProduct.getQuantity() == null ? BigDecimal.ZERO : dbProduct.getQuantity(); |
| | | int lineStockStatus; |
| | | if (newStocked.compareTo(BigDecimal.ZERO) <= 0) { |
| | | lineStockStatus = 0; |
| | | } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) { |
| | | lineStockStatus = 1; |
| | | } else { |
| | | lineStockStatus = 2; |
| | | } |
| | | dbProduct.setStockedQuantity(newStocked); |
| | | dbProduct.setProductStockStatus(lineStockStatus); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | | List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId)); |
| | | boolean anyInbound = ledgerAllProducts.stream().anyMatch(p -> { |
| | | BigDecimal sq = p.getStockedQuantity(); |
| | | return sq != null && sq.compareTo(BigDecimal.ZERO) > 0; |
| | | }); |
| | | boolean allLinesFull = ledgerAllProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2)); |
| | | salesLedger.setStockStatus(allLinesFull ? 2 : (anyInbound ? 1 : 0)); |
| | | baseMapper.updateById(salesLedger); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scanInboundUnqualified(SalesScanInboundDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new ServiceException("销售订单不合格入库失败,入库数据不能为空"); |
| | | } |
| | | SalesLedger salesLedger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("不合格入库失败,销售订单不存在"); |
| | | } |
| | | if (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("不合格入库失败,该销售订单已发货"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("销售订单不合格入库失败,入库产品不能为空"); |
| | | } |
| | | Map<Long, BigDecimal> inboundQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct inbound : dto.getSalesLedgerProductList()) { |
| | | if (inbound == null || inbound.getId() == null) { |
| | | throw new ServiceException("不合格入库失败,销售产品信息不完整"); |
| | | } |
| | | BigDecimal inboundQty = inbound.getStockedQuantity(); |
| | | if (inboundQty == null) { |
| | | throw new ServiceException("不合格入库失败,入库数量不能为空"); |
| | | } |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("不合格入库失败,入库数量不能为负数"); |
| | | } |
| | | inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add); |
| | | } |
| | | List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet())); |
| | | if (CollectionUtils.isEmpty(selectedProducts)) { |
| | | throw new ServiceException("不合格入库失败,未查询到入库产品"); |
| | | } |
| | | if (selectedProducts.size() != inboundQtyByLineId.size()) { |
| | | throw new ServiceException("不合格入库失败,部分产品不存在"); |
| | | } |
| | | for (SalesLedgerProduct selectedProduct : selectedProducts) { |
| | | if (!Objects.equals(selectedProduct.getSalesLedgerId(), salesLedger.getId())) { |
| | | throw new ServiceException("不合格入库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (!Objects.equals(selectedProduct.getType(), SaleEnum.SALE.getCode())) { |
| | | throw new ServiceException("不合格入库失败,仅支持销售订单产品行"); |
| | | } |
| | | if (selectedProduct.getProductModelId() == null) { |
| | | throw new ServiceException("不合格入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | } |
| | | String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED); |
| | | if (StringUtils.isEmpty(approveUserIds)) { |
| | | throw new ServiceException("不合格入库失败,请选择审批人"); |
| | | } |
| | | String lines = inboundQtyByLineId.entrySet().stream().map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString()).collect(Collectors.joining(",")); |
| | | String reason = "销售扫码不合格入库审批:" + salesLedger.getSalesContractNo(); |
| | | String remark = "scanUnqualified:" + salesLedger.getId() + ":" + lines; |
| | | ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveRemark, remark).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1")); |
| | | if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) { |
| | | throw new ServiceException("不合格入库失败,该申请已提交审批"); |
| | | } |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | ApproveProcessVO approveProcessVO = new ApproveProcessVO(); |
| | | approveProcessVO.setApproveType(ApproveTypeEnum.STOCK_IN.getCode()); |
| | | approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId()); |
| | | approveProcessVO.setApproveReason(reason); |
| | | approveProcessVO.setApproveRemark(remark); |
| | | approveProcessVO.setApproveUserIds(approveUserIds); |
| | | approveProcessVO.setApproveUser(loginUser.getUserId()); |
| | | approveProcessVO.setApproveTime(LocalDate.now().toString()); |
| | | try { |
| | | approveProcessService.addApprove(approveProcessVO); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("不合格入库审批发起失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void executeSalesScanInboundUnqualifiedApproved(Long salesLedgerId, Map<Long, BigDecimal> inboundQtyByLineId) { |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerId); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("不合格入库失败,销售订单不存在"); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal inboundThisLine = entry.getValue(); |
| | | if (inboundThisLine == null || inboundThisLine.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId); |
| | | if (dbProduct == null) { |
| | | throw new ServiceException("不合格入库失败,销售产品不存在"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getSalesLedgerId(), ledgerId)) { |
| | | throw new ServiceException("不合格入库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getType(), SaleEnum.SALE.getCode())) { |
| | | throw new ServiceException("不合格入库失败,仅支持销售订单产品行"); |
| | | } |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("不合格入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine, StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId()); |
| | | BigDecimal oldUnStocked = dbProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedStockedQuantity(); |
| | | dbProduct.setUnqualifiedStockedQuantity(oldUnStocked.add(inboundThisLine)); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | | } |
| | | |
| | | private String resolveApproveUserIds(String approveUserIds, Long salesLedgerId, Integer bizType) { |
| | | if (StringUtils.isNotEmpty(approveUserIds)) { |
| | | return approveUserIds; |
| | | } |
| | | LambdaQueryWrapper<ApproveProcess> wrapper = new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1"); |
| | | if (Objects.equals(bizType, INBOUND_BIZ_TYPE_WEB)) { |
| | | wrapper.likeRight(ApproveProcess::getApproveReason, "入库审批:").likeRight(ApproveProcess::getApproveRemark, "salesStock:" + salesLedgerId + ":"); |
| | | } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_QUALIFIED)) { |
| | | wrapper.likeRight(ApproveProcess::getApproveReason, "销售扫码合格入库审批:").likeRight(ApproveProcess::getApproveRemark, "scanQualified:" + salesLedgerId + ":"); |
| | | } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED)) { |
| | | wrapper.likeRight(ApproveProcess::getApproveReason, "销售扫码不合格入库审批:").likeRight(ApproveProcess::getApproveRemark, "scanUnqualified:" + salesLedgerId + ":"); |
| | | } else { |
| | | return null; |
| | | } |
| | | ApproveProcess latest = approveProcessService.getOne(wrapper); |
| | | return latest == null ? null : latest.getApproveUserIds(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scanOutbound(SalesScanInboundDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new ServiceException("销售订单出库失败,出库数据不能为空"); |
| | | } |
| | | SalesLedger salesLedger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("出库失败,销售订单不存在"); |
| | | } |
| | | if (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("出库失败,该销售订单已发货"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("销售订单出库失败,出库产品不能为空"); |
| | | } |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | Map<Long, BigDecimal> outboundQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct line : dto.getSalesLedgerProductList()) { |
| | | if (line == null || line.getId() == null) { |
| | | throw new ServiceException("出库失败,销售产品信息不完整"); |
| | | } |
| | | BigDecimal outboundQty = line.getStockedQuantity(); |
| | | if (outboundQty == null) { |
| | | throw new ServiceException("出库失败,出库数量不能为空"); |
| | | } |
| | | if (outboundQty.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("出库失败,出库数量不能为负数"); |
| | | } |
| | | outboundQtyByLineId.merge(line.getId(), outboundQty, BigDecimal::add); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : outboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal outboundThisLine = entry.getValue(); |
| | | if (outboundThisLine.compareTo(BigDecimal.ZERO) == 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId); |
| | | if (dbProduct == null) { |
| | | throw new ServiceException("出库失败,销售产品不存在"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getSalesLedgerId(), ledgerId) || !Objects.equals(dbProduct.getType(), saleType)) { |
| | | throw new ServiceException("出库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("出库失败,产品规格未维护,无法出库"); |
| | | } |
| | | stockUtils.assertQualifiedAvailable(dbProduct.getProductModelId(), outboundThisLine); |
| | | |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordId(dbProduct.getId()); |
| | | stockInventoryDto.setRecordType(StockOutQualifiedRecordTypeEnum.SALE_SCAN_STOCK_OUT.getCode()); |
| | | stockInventoryDto.setQualitity(outboundThisLine); |
| | | stockInventoryDto.setProductModelId(dbProduct.getProductModelId()); |
| | | stockInventoryDto.setSalesLedgerId(ledgerId); |
| | | stockInventoryDto.setSalesLedgerProductId(dbProduct.getId()); |
| | | stockInventoryService.subtractStockInventory(stockInventoryDto); |
| | | |
| | | BigDecimal oldShipped = dbProduct.getShippedQuantity() == null ? BigDecimal.ZERO : dbProduct.getShippedQuantity(); |
| | | dbProduct.setShippedQuantity(oldShipped.add(outboundThisLine)); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | | List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId)); |
| | | boolean anyInbound = ledgerAllProducts.stream().anyMatch(p -> { |
| | | BigDecimal sq = p.getStockedQuantity(); |
| | | return sq != null && sq.compareTo(BigDecimal.ZERO) > 0; |
| | | }); |
| | | boolean allLinesFull = ledgerAllProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2)); |
| | | salesLedger.setStockStatus(allLinesFull ? 2 : (anyInbound ? 1 : 0)); |
| | | baseMapper.updateById(salesLedger); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scanOutboundUnqualified(SalesScanInboundDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new ServiceException("销售订单不合格出库失败,出库数据不能为空"); |
| | | } |
| | | SalesLedger salesLedger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("不合格出库失败,销售订单不存在"); |
| | | } |
| | | if (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("不合格出库失败,该销售订单已发货"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("销售订单不合格出库失败,出库产品不能为空"); |
| | | } |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | Map<Long, BigDecimal> outboundQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct line : dto.getSalesLedgerProductList()) { |
| | | if (line == null || line.getId() == null) { |
| | | throw new ServiceException("不合格出库失败,销售产品信息不完整"); |
| | | } |
| | | BigDecimal outboundQty = line.getStockedQuantity(); |
| | | if (outboundQty == null) { |
| | | throw new ServiceException("不合格出库失败,出库数量不能为空"); |
| | | } |
| | | if (outboundQty.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("不合格出库失败,出库数量不能为负数"); |
| | | } |
| | | outboundQtyByLineId.merge(line.getId(), outboundQty, BigDecimal::add); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : outboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal outboundThisLine = entry.getValue(); |
| | | if (outboundThisLine.compareTo(BigDecimal.ZERO) == 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(salesLedgerProductId); |
| | | if (dbProduct == null) { |
| | | throw new ServiceException("不合格出库失败,销售产品不存在"); |
| | | } |
| | | if (!Objects.equals(dbProduct.getSalesLedgerId(), ledgerId) || !Objects.equals(dbProduct.getType(), saleType)) { |
| | | throw new ServiceException("不合格出库失败,销售产品与订单不匹配"); |
| | | } |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("不合格出库失败,产品规格未维护,无法出库"); |
| | | } |
| | | BigDecimal unStocked = dbProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedStockedQuantity(); |
| | | BigDecimal unShipped = dbProduct.getUnqualifiedShippedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedShippedQuantity(); |
| | | BigDecimal canUnShip = unStocked.subtract(unShipped); |
| | | if (outboundThisLine.compareTo(canUnShip) > 0) { |
| | | throw new ServiceException("不合格出库失败,出库数量不能大于不合格入库数量"); |
| | | } |
| | | stockUtils.assertUnqualifiedAvailable(dbProduct.getProductModelId(), outboundThisLine); |
| | | stockUtils.subtractUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), outboundThisLine, StockOutUnQualifiedRecordTypeEnum.SALE_SCAN_UNSTOCK_OUT.getCode(), dbProduct.getId()); |
| | | |
| | | dbProduct.setUnqualifiedShippedQuantity(unShipped.add(outboundThisLine)); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void shippingImport(MultipartFile file) { |
| | | if (file == null || file.isEmpty()) { |
| | | throw new ServiceException("导入失败,导入文件数据不能为空"); |
| | | } |
| | | List<SalesShippingImportDto> list; |
| | | try { |
| | | ExcelUtil<SalesShippingImportDto> excelUtil = new ExcelUtil<>(SalesShippingImportDto.class); |
| | | list = excelUtil.importExcel(file.getInputStream()); |
| | | } catch (Exception e) { |
| | | log.error("销售发货历史数据导入-已发货导入失败: {}", e.getMessage()); |
| | | throw new ServiceException("导入失败,数据读取异常"); |
| | | } |
| | | if (CollectionUtils.isEmpty(list)) { |
| | | throw new ServiceException("导入失败,文件数据为空"); |
| | | } |
| | | Map<String, List<SalesShippingImportDto>> groupedByOrderNo = list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SalesShippingImportDto::getOrderNo, LinkedHashMap::new, Collectors.toList())); |
| | | |
| | | for (Map.Entry<String, List<SalesShippingImportDto>> entry : groupedByOrderNo.entrySet()) { |
| | | String orderNo = entry.getKey(); |
| | | if (!StringUtils.hasText(orderNo)) { |
| | | throw new ServiceException("导入失败,存在订单编号为空的数据"); |
| | | } |
| | | List<SalesShippingImportDto> rowList = entry.getValue(); |
| | | if (CollectionUtils.isEmpty(rowList)) { |
| | | continue; |
| | | } |
| | | SalesLedger ledger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1")); |
| | | if (ledger == null) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]不存在,无法补录已发货数据"); |
| | | } |
| | | List<SalesLedgerProduct> dbProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode())); |
| | | if (CollectionUtils.isEmpty(dbProducts)) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]没有销售产品,无法补录发货"); |
| | | } |
| | | Map<String, List<SalesLedgerProduct>> productByCategory = dbProducts.stream().collect(Collectors.groupingBy(p -> StringUtils.hasText(p.getProductCategory()) ? p.getProductCategory().trim() : "")); |
| | | Set<String> importedRowKeys = new HashSet<>(); |
| | | |
| | | for (SalesShippingImportDto row : rowList) { |
| | | BigDecimal shipQty = defaultDecimal(row.getQuantity()); |
| | | if (shipQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]存在数量小于等于0的数据"); |
| | | } |
| | | String rowKey = buildShippingRowKey(ledger.getId(), row); |
| | | if (!importedRowKeys.add(rowKey)) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]存在重复发货明细行"); |
| | | } |
| | | Map<SalesLedgerProduct, BigDecimal> allocations = allocateShippingProductLines(orderNo, row, productByCategory, dbProducts); |
| | | for (Map.Entry<SalesLedgerProduct, BigDecimal> alloc : allocations.entrySet()) { |
| | | SalesLedgerProduct dbProduct = alloc.getKey(); |
| | | BigDecimal allocQty = alloc.getValue(); |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]产品规格未维护,无法补录出库"); |
| | | } |
| | | BigDecimal oldShipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | BigDecimal newShipped = oldShipped.add(allocQty); |
| | | dbProduct.setStockedQuantity(defaultDecimal(dbProduct.getQuantity())); |
| | | dbProduct.setShippedQuantity(newShipped); |
| | | updateProductStockStatus(dbProduct); |
| | | dbProduct.fillRemainingQuantity(); |
| | | updateProductShipStatus(dbProduct); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | |
| | | ShippingInfo shippingInfo = new ShippingInfo(); |
| | | shippingInfo.setSalesLedgerId(ledger.getId()); |
| | | shippingInfo.setSalesLedgerProductId(dbProduct.getId()); |
| | | shippingInfo.setStatus("已发货"); |
| | | shippingInfo.setShippingNo(row.getShippingNo()); |
| | | shippingInfo.setType("货车"); |
| | | shippingInfo.setShippingCarNumber("无"); |
| | | shippingInfo.setShippingDate(row.getReportDate()); |
| | | long existedShippingCount = shippingInfoMapper.selectCount(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerId, ledger.getId()).eq(ShippingInfo::getSalesLedgerProductId, dbProduct.getId()).eq(StringUtils.hasText(row.getShippingNo()), ShippingInfo::getShippingNo, row.getShippingNo()).eq(row.getReportDate() != null, ShippingInfo::getShippingDate, row.getReportDate())); |
| | | if (existedShippingCount > 0) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]存在重复发货记录,请勿重复导入"); |
| | | } |
| | | shippingInfoMapper.insert(shippingInfo); |
| | | } |
| | | } |
| | | |
| | | List<SalesLedgerProduct> latestProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode())); |
| | | boolean allShipped = CollectionUtils.isNotEmpty(latestProducts) && latestProducts.stream().allMatch(p -> { |
| | | BigDecimal qty = defaultDecimal(p.getQuantity()); |
| | | BigDecimal shipped = defaultDecimal(p.getShippedQuantity()); |
| | | return shipped.compareTo(qty) >= 0; |
| | | }); |
| | | if (allShipped && rowList.get(0).getReportDate() != null) { |
| | | ledger.setDeliveryDate(DateUtils.toLocalDate(rowList.get(0).getReportDate())); |
| | | } |
| | | ledger.setDeliveryStatus(allShipped ? 5 : 1); |
| | | salesLedgerMapper.updateById(ledger); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void notShippingImport(MultipartFile file) { |
| | | if (file == null || file.isEmpty()) { |
| | | throw new ServiceException("导入失败,导入文件数据不能为空"); |
| | | } |
| | | List<SalesNotShippingImportDto> list; |
| | | try { |
| | | ExcelUtil<SalesNotShippingImportDto> excelUtil = new ExcelUtil<>(SalesNotShippingImportDto.class); |
| | | list = excelUtil.importExcel(file.getInputStream()); |
| | | } catch (Exception e) { |
| | | log.error("销售发货历史数据导入-未发货导入失败: {}", e.getMessage()); |
| | | throw new ServiceException("导入失败,数据读取异常"); |
| | | } |
| | | if (CollectionUtils.isEmpty(list)) { |
| | | throw new ServiceException("导入失败,文件数据为空"); |
| | | } |
| | | List<SysUser> allUsers = sysUserMapper.selectList(null); |
| | | Map<String, SysUser> userByNickNameMap = allUsers.stream().filter(Objects::nonNull).filter(u -> StringUtils.hasText(u.getNickName())).collect(Collectors.toMap(SysUser::getNickName, Function.identity(), (a, b) -> a)); |
| | | Map<String, SysUser> userByUserNameMap = allUsers.stream().filter(Objects::nonNull).filter(u -> StringUtils.hasText(u.getUserName())).collect(Collectors.toMap(SysUser::getUserName, Function.identity(), (a, b) -> a)); |
| | | |
| | | Map<String, Customer> customerNameMap = customerMapper.selectList(null).stream().filter(Objects::nonNull).filter(c -> StringUtils.hasText(c.getCustomerName())).collect(Collectors.toMap(Customer::getCustomerName, Function.identity(), (a, b) -> a)); |
| | | List<CustomerRegions> allRegions = customerRegionsService.list(); |
| | | CustomerRegions hebiRegion = allRegions.stream().filter(Objects::nonNull).filter(r -> "鹤壁".equals(r.getRegionsName())).findFirst().orElseGet(() -> { |
| | | CustomerRegions region = new CustomerRegions(); |
| | | region.setRegionsName("鹤壁"); |
| | | region.setParentId(0L); |
| | | customerRegionsService.save(region); |
| | | return region; |
| | | }); |
| | | Map<String, Product> productNameMap = productMapper.selectList(null).stream().filter(Objects::nonNull).filter(p -> StringUtils.hasText(p.getProductName())).collect(Collectors.toMap(Product::getProductName, Function.identity(), (a, b) -> a)); |
| | | Product finishedGoodsParent = productNameMap.get("成品"); |
| | | if (finishedGoodsParent == null || finishedGoodsParent.getId() == null) { |
| | | finishedGoodsParent = new Product(); |
| | | finishedGoodsParent.setProductName("成品"); |
| | | finishedGoodsParent.setParentId(null); |
| | | productMapper.insert(finishedGoodsParent); |
| | | productNameMap.put("成品", finishedGoodsParent); |
| | | } |
| | | Map<String, ProductModel> productModelKeyMap = productModelMapper.selectList(null).stream().filter(Objects::nonNull).filter(m -> m.getProductId() != null && StringUtils.hasText(m.getModel())).collect(Collectors.toMap(m -> buildProductModelKey(m.getProductId(), m.getModel()), Function.identity(), (a, b) -> a)); |
| | | |
| | | List<String> extraProcessNames = Arrays.asList("打孔", "挖缺", "安全角", "磨边"); |
| | | Map<String, SalesLedgerProductProcess> processMap = salesLedgerProductProcessService.list(new LambdaQueryWrapper<SalesLedgerProductProcess>().in(SalesLedgerProductProcess::getProcessName, extraProcessNames)).stream().filter(Objects::nonNull).filter(p -> StringUtils.hasText(p.getProcessName())).collect(Collectors.toMap(SalesLedgerProductProcess::getProcessName, Function.identity(), (a, b) -> a)); |
| | | List<ProcessRoute> processRoutes = processRouteMapper.selectList(new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getProductModelId, 0L)); |
| | | Map<String, ProcessRoute> routeNameMap = processRoutes.stream().filter(Objects::nonNull).filter(r -> StringUtils.hasText(r.getProcessRouteName())).collect(Collectors.toMap(r -> normalizeRouteFlowKey(r.getProcessRouteName()), Function.identity(), this::chooseBetterRoute)); |
| | | Map<Long, List<ProcessRouteItem>> routeItemMap = Collections.emptyMap(); |
| | | List<Long> routeIds = processRoutes.stream().map(ProcessRoute::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(routeIds)) { |
| | | routeItemMap = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().in(ProcessRouteItem::getRouteId, routeIds).orderByAsc(ProcessRouteItem::getDragSort).orderByAsc(ProcessRouteItem::getId)).stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ProcessRouteItem::getRouteId)); |
| | | } |
| | | |
| | | Map<String, List<SalesNotShippingImportDto>> groupedByOrderNo = list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SalesNotShippingImportDto::getOrderNo, LinkedHashMap::new, Collectors.toList())); |
| | | |
| | | for (Map.Entry<String, List<SalesNotShippingImportDto>> entry : groupedByOrderNo.entrySet()) { |
| | | String orderNo = entry.getKey(); |
| | | if (!StringUtils.hasText(orderNo)) { |
| | | throw new ServiceException("导入失败,存在订单编号为空的数据"); |
| | | } |
| | | List<SalesNotShippingImportDto> rowList = entry.getValue(); |
| | | if (CollectionUtils.isEmpty(rowList)) { |
| | | continue; |
| | | } |
| | | SalesNotShippingImportDto first = rowList.get(0); |
| | | SalesLedger exists = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1")); |
| | | if (exists != null) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]已存在"); |
| | | } |
| | | |
| | | SalesLedger ledger = new SalesLedger(); |
| | | SysUser creatorUser = resolveImportUser(first.getCreator(), userByNickNameMap, userByUserNameMap, "制单员", orderNo); |
| | | ledger.setSalesContractNo(orderNo); |
| | | ledger.setCustomerContractNo(first.getContractNo()); |
| | | ledger.setProjectName(first.getProjectName()); |
| | | ledger.setSalesman(first.getSalesman()); |
| | | Customer customer = getOrCreateImportCustomer(first.getCustomerName(), customerNameMap, hebiRegion.getId()); |
| | | ledger.setCustomerName(customer.getCustomerName()); |
| | | ledger.setRemarks(first.getRemark()); |
| | | ledger.setEntryPerson(String.valueOf(creatorUser.getUserId())); |
| | | ledger.setEntryDate(first.getReportDate()); |
| | | if (first.getReportDate() != null) { |
| | | ledger.setExecutionDate(DateUtils.toLocalDate(first.getReportDate())); |
| | | } |
| | | ledger.setDeliveryDate(first.getDeliveryDeadline() == null ? (first.getReportDate() == null ? LocalDate.now().plusDays(7) : DateUtils.toLocalDate(first.getReportDate()).plusDays(7)) : DateUtils.toLocalDate(first.getDeliveryDeadline())); |
| | | ledger.setDeliveryStatus(1); |
| | | ledger.setStockStatus(0); |
| | | |
| | | ledger.setCustomerId(customer.getId()); |
| | | ledger.setCustomerContractNo(StringUtils.hasText(ledger.getCustomerContractNo()) ? ledger.getCustomerContractNo() : customer.getTaxpayerIdentificationNumber()); |
| | | |
| | | ledger.setContractAmount(BigDecimal.ZERO); |
| | | salesLedgerMapper.insert(ledger); |
| | | bindImportProcessRoute(ledger.getId(), rowList, routeNameMap, routeItemMap); |
| | | |
| | | BigDecimal contractAmount = BigDecimal.ZERO; |
| | | for (SalesNotShippingImportDto row : rowList) { |
| | | SalesLedgerProduct product = new SalesLedgerProduct(); |
| | | product.setSalesLedgerId(ledger.getId()); |
| | | product.setType(SaleEnum.SALE.getCode()); |
| | | String specificationModel = buildSpecificationModel(row); |
| | | Product importProduct = resolveOrCreateImportProduct(row, productNameMap, finishedGoodsParent, orderNo); |
| | | ProductModel importProductModel = resolveOrCreateImportProductModel(importProduct, specificationModel, row.getGlassThickness(), productModelKeyMap); |
| | | product.setProductCategory(row.getProductSubCategory()); |
| | | product.setSpecificationModel(specificationModel); |
| | | product.setProductId(importProduct.getId()); |
| | | product.setProductModelId(importProductModel.getId()); |
| | | product.setFloorCode(row.getFloorNo()); |
| | | product.setWidth(defaultDecimal(row.getWidth())); |
| | | product.setHeight(defaultDecimal(row.getHeight())); |
| | | product.setQuantity(defaultDecimal(row.getQuantity())); |
| | | product.setActualPieceArea(defaultDecimal(row.getActualSingleArea())); |
| | | product.setActualTotalArea(defaultDecimal(row.getActualTotalArea())); |
| | | product.setSettlePieceArea(defaultDecimal(row.getSettlementSingleArea())); |
| | | product.setSettleTotalArea(defaultDecimal(row.getSettlementTotalArea())); |
| | | product.setTaxInclusiveUnitPrice(defaultDecimal(row.getUnitPrice())); |
| | | product.setPerimeter(defaultDecimal(row.getPerimeter())); |
| | | product.setHeavyBox(defaultDecimal(row.getHeavyBox())); |
| | | product.setProcessRequirement(row.getProcessRequirement()); |
| | | product.setRemark(StringUtils.hasText(row.getAuditRemark()) ? row.getAuditRemark() : row.getRemark()); |
| | | product.setApproveStatus(0); |
| | | product.setProductStockStatus(0); |
| | | product.setRegister(creatorUser.getNickName()); |
| | | product.setRegisterDate(row.getReportDate() == null ? LocalDateTime.now() : LocalDateTime.ofInstant(row.getReportDate().toInstant(), ZoneId.systemDefault())); |
| | | |
| | | BigDecimal qty = defaultDecimal(product.getQuantity()); |
| | | if (qty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]存在数量小于等于0的数据"); |
| | | } |
| | | |
| | | BigDecimal lineAmount = defaultDecimal(row.getGlassAmount()).add(defaultDecimal(row.getOtherProcessFee())); |
| | | if (lineAmount.compareTo(BigDecimal.ZERO) <= 0 && product.getTaxInclusiveUnitPrice().compareTo(BigDecimal.ZERO) > 0 && product.getSettleTotalArea().compareTo(BigDecimal.ZERO) > 0) { |
| | | lineAmount = product.getTaxInclusiveUnitPrice().multiply(product.getSettleTotalArea()).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | product.setTaxRate(BigDecimal.ZERO); |
| | | product.setTaxInclusiveTotalPrice(lineAmount); |
| | | product.setTaxExclusiveTotalPrice(lineAmount); |
| | | product.setNoInvoiceNum(qty); |
| | | product.setNoInvoiceAmount(lineAmount); |
| | | product.setPendingInvoiceTotal(lineAmount); |
| | | product.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.insert(product); |
| | | |
| | | List<SalesLedgerProductProcess> bindProcessList = buildImportProcessBinds(row, processMap); |
| | | if (CollectionUtils.isNotEmpty(bindProcessList)) { |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(bindProcessList, product.getId()); |
| | | } |
| | | |
| | | salesLedgerProductServiceImpl.addProductionData(product); |
| | | contractAmount = contractAmount.add(lineAmount); |
| | | } |
| | | |
| | | ledger.setContractAmount(contractAmount); |
| | | salesLedgerMapper.updateById(ledger); |
| | | } |
| | | } |
| | | |
| | | private List<SalesLedgerProductProcess> buildImportProcessBinds(SalesNotShippingImportDto row, Map<String, SalesLedgerProductProcess> processMap) { |
| | | LinkedHashMap<String, Integer> processQuantityMap = new LinkedHashMap<>(); |
| | | mergeProcessQuantity(processQuantityMap, "打孔", toProcessQuantity(row.getDrilling())); |
| | | mergeProcessQuantity(processQuantityMap, "挖缺", toProcessQuantity(row.getNotching())); |
| | | mergeProcessQuantity(processQuantityMap, "安全角", toProcessQuantity(row.getSafetyCorner())); |
| | | mergeProcessQuantity(processQuantityMap, "磨边", toProcessQuantity(row.getGrindingIrregular())); |
| | | |
| | | List<SalesLedgerProductProcess> result = new ArrayList<>(); |
| | | for (Map.Entry<String, Integer> entry : processQuantityMap.entrySet()) { |
| | | if (entry.getValue() == null || entry.getValue() <= 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProductProcess process = processMap.get(entry.getKey()); |
| | | if (process == null || process.getId() == null) { |
| | | log.warn("导入工艺未找到配置, processName={}, orderNo={}", entry.getKey(), row.getOrderNo()); |
| | | continue; |
| | | } |
| | | SalesLedgerProductProcess bind = new SalesLedgerProductProcess(); |
| | | bind.setId(process.getId()); |
| | | bind.setQuantity(entry.getValue()); |
| | | result.add(bind); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private void bindImportProcessRoute(Long salesLedgerId, List<SalesNotShippingImportDto> rowList, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) { |
| | | String flowKey = rowList.stream().map(SalesNotShippingImportDto::getProcessFlow).filter(StringUtils::hasText).map(this::normalizeRouteFlowKey).filter(StringUtils::hasText).findFirst().orElse(""); |
| | | if (!StringUtils.hasText(flowKey)) { |
| | | throw new ServiceException("导入失败,订单工艺流程不能为空"); |
| | | } |
| | | ProcessRoute route = routeNameMap.get(flowKey); |
| | | if (route == null || route.getId() == null) { |
| | | route = createImportProcessRoute(flowKey, routeNameMap, routeItemMap); |
| | | } |
| | | List<ProcessRouteItem> routeItems = routeItemMap.getOrDefault(route.getId(), Collections.emptyList()); |
| | | if (CollectionUtils.isEmpty(routeItems)) { |
| | | route = createImportProcessRoute(flowKey, routeNameMap, routeItemMap); |
| | | routeItems = routeItemMap.getOrDefault(route.getId(), Collections.emptyList()); |
| | | if (CollectionUtils.isEmpty(routeItems)) { |
| | | throw new ServiceException("导入失败,工艺路线[" + flowKey + "]未配置工艺节点"); |
| | | } |
| | | } |
| | | List<SalesLedgerProcessRoute> bindList = new ArrayList<>(); |
| | | for (ProcessRouteItem item : routeItems) { |
| | | SalesLedgerProcessRoute bind = new SalesLedgerProcessRoute(); |
| | | bind.setSalesLedgerId(salesLedgerId); |
| | | bind.setProcessRouteId(route.getId()); |
| | | bind.setProcessRouteItemId(item.getId()); |
| | | bind.setDragSort(item.getDragSort()); |
| | | bindList.add(bind); |
| | | } |
| | | salesLedgerProcessRouteService.saveBatch(bindList); |
| | | } |
| | | |
| | | private ProcessRoute createImportProcessRoute(String flowKey, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) { |
| | | List<String> processNames = Arrays.stream(flowKey.split("->")).filter(StringUtils::hasText).map(String::trim).collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(processNames)) { |
| | | throw new ServiceException("导入失败,工艺路线[" + flowKey + "]解析失败"); |
| | | } |
| | | ProcessRoute route = new ProcessRoute(); |
| | | route.setProductModelId(0L); |
| | | route.setProcessRouteName(flowKey); |
| | | route.setIsDefault(0); |
| | | route.setDescription(""); |
| | | route.setProcessRouteCode("AUTO_" + System.currentTimeMillis()); |
| | | processRouteMapper.insert(route); |
| | | List<ProcessRouteItem> routeItems = new ArrayList<>(); |
| | | for (int i = 0; i < processNames.size(); i++) { |
| | | ProcessRouteItem item = new ProcessRouteItem(); |
| | | item.setRouteId(route.getId()); |
| | | item.setProductModelId(0L); |
| | | item.setProcessId(0L); |
| | | item.setProcessName(processNames.get(i)); |
| | | item.setDragSort(i + 1); |
| | | item.setIsQuality(Boolean.TRUE); |
| | | processRouteItemMapper.insert(item); |
| | | routeItems.add(item); |
| | | } |
| | | routeNameMap.put(flowKey, route); |
| | | routeItemMap.put(route.getId(), routeItems); |
| | | return route; |
| | | } |
| | | |
| | | private void mergeProcessQuantity(Map<String, Integer> processQuantityMap, String processName, Integer quantity) { |
| | | if (!StringUtils.hasText(processName) || quantity == null || quantity <= 0) { |
| | | return; |
| | | } |
| | | Integer old = processQuantityMap.get(processName); |
| | | if (old == null || old <= 0) { |
| | | processQuantityMap.put(processName, quantity); |
| | | } |
| | | } |
| | | |
| | | private String normalizeRouteFlowKey(String processFlow) { |
| | | if (!StringUtils.hasText(processFlow)) { |
| | | return ""; |
| | | } |
| | | return Arrays.stream(processFlow.trim().split("\\s*(?:->|→|=>|>)\\s*")).filter(StringUtils::hasText).map(String::trim).collect(Collectors.joining("->")); |
| | | } |
| | | |
| | | private ProcessRoute chooseBetterRoute(ProcessRoute a, ProcessRoute b) { |
| | | if (a == null) { |
| | | return b; |
| | | } |
| | | if (b == null) { |
| | | return a; |
| | | } |
| | | boolean aDefault = Objects.equals(a.getIsDefault(), 1); |
| | | boolean bDefault = Objects.equals(b.getIsDefault(), 1); |
| | | if (aDefault != bDefault) { |
| | | return aDefault ? a : b; |
| | | } |
| | | LocalDateTime aTime = a.getCreateTime(); |
| | | LocalDateTime bTime = b.getCreateTime(); |
| | | if (aTime == null) { |
| | | return b; |
| | | } |
| | | if (bTime == null) { |
| | | return a; |
| | | } |
| | | return bTime.isAfter(aTime) ? b : a; |
| | | } |
| | | |
| | | private Integer toProcessQuantity(BigDecimal value) { |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | if (value.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return 0; |
| | | } |
| | | return value.setScale(0, RoundingMode.HALF_UP).intValue(); |
| | | } |
| | | |
| | | private SysUser resolveImportUser(String rawName, Map<String, SysUser> userByNickNameMap, Map<String, SysUser> userByUserNameMap, String fieldName, String orderNo) { |
| | | if (!StringUtils.hasText(rawName)) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]的[" + fieldName + "]不能为空"); |
| | | } |
| | | String key = rawName.trim(); |
| | | SysUser user = userByNickNameMap.get(key); |
| | | if (user == null) { |
| | | user = userByUserNameMap.get(key); |
| | | } |
| | | if (user == null || user.getUserId() == null) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]的[" + fieldName + ":" + key + "]未匹配到人员"); |
| | | } |
| | | return user; |
| | | } |
| | | |
| | | private Customer getOrCreateImportCustomer(String customerName, Map<String, Customer> customerNameMap, Long hebiRegionId) { |
| | | if (!StringUtils.hasText(customerName)) { |
| | | throw new ServiceException("导入失败,客户名称不能为空"); |
| | | } |
| | | String key = customerName.trim(); |
| | | Customer exists = customerNameMap.get(key); |
| | | if (exists != null && exists.getId() != null) { |
| | | return exists; |
| | | } |
| | | Customer customer = new Customer(); |
| | | customer.setCustomerName(key); |
| | | customer.setRegionsId(hebiRegionId); |
| | | customerMapper.insert(customer); |
| | | customerNameMap.put(key, customer); |
| | | return customer; |
| | | } |
| | | |
| | | private Product resolveOrCreateImportProduct(SalesNotShippingImportDto row, Map<String, Product> productNameMap, Product finishedGoodsParent, String orderNo) { |
| | | String productName = row.getProductName(); |
| | | if (StringUtils.hasText(productName)) { |
| | | Product product = productNameMap.get(productName.trim()); |
| | | if (product != null && product.getId() != null) { |
| | | return product; |
| | | } |
| | | } |
| | | String productSubCategory = row.getProductSubCategory(); |
| | | if (StringUtils.hasText(productSubCategory)) { |
| | | Product product = productNameMap.get(productSubCategory.trim()); |
| | | if (product != null && product.getId() != null) { |
| | | return product; |
| | | } |
| | | } |
| | | String newProductName = buildCategoryProductName(row); |
| | | if (!StringUtils.hasText(newProductName)) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]产品名称和产品分类均为空"); |
| | | } |
| | | Product created = new Product(); |
| | | created.setParentId(finishedGoodsParent == null ? null : finishedGoodsParent.getId()); |
| | | created.setProductName(newProductName); |
| | | productMapper.insert(created); |
| | | productNameMap.put(newProductName, created); |
| | | return created; |
| | | } |
| | | |
| | | private ProductModel resolveOrCreateImportProductModel(Product product, String modelName, BigDecimal thickness, Map<String, ProductModel> productModelKeyMap) { |
| | | if (product == null || product.getId() == null || !StringUtils.hasText(modelName)) { |
| | | throw new ServiceException("导入失败,产品规格数据不完整"); |
| | | } |
| | | String key = buildProductModelKey(product.getId(), modelName); |
| | | ProductModel exists = productModelKeyMap.get(key); |
| | | if (exists != null && exists.getId() != null) { |
| | | return exists; |
| | | } |
| | | ProductModel created = new ProductModel(); |
| | | created.setProductId(product.getId()); |
| | | created.setModel(modelName.trim()); |
| | | created.setThickness(thickness); |
| | | productModelMapper.insert(created); |
| | | productModelKeyMap.put(key, created); |
| | | return created; |
| | | } |
| | | |
| | | private String buildSpecificationModel(SalesNotShippingImportDto row) { |
| | | if (StringUtils.hasText(row.getProductName())) { |
| | | return row.getProductName().trim(); |
| | | } |
| | | if (StringUtils.hasText(row.getProductSubCategory())) { |
| | | return row.getProductSubCategory().trim(); |
| | | } |
| | | if (StringUtils.hasText(row.getProductCategory())) { |
| | | return row.getProductCategory().trim(); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private String buildCategoryProductName(SalesNotShippingImportDto row) { |
| | | String category = row.getProductCategory(); |
| | | String subCategory = row.getProductSubCategory(); |
| | | if (StringUtils.hasText(category) && StringUtils.hasText(subCategory)) { |
| | | return category.trim() + "-" + subCategory.trim(); |
| | | } |
| | | if (StringUtils.hasText(subCategory)) { |
| | | return subCategory.trim(); |
| | | } |
| | | if (StringUtils.hasText(category)) { |
| | | return category.trim(); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private String buildProductModelKey(Long productId, String modelName) { |
| | | return productId + "||" + modelName.trim(); |
| | | } |
| | | |
| | | private String buildCategoryProductName(SalesShippingImportDto row) { |
| | | String category = row.getProductCategory(); |
| | | String subCategory = row.getProductSubCategory(); |
| | | if (StringUtils.hasText(category) && StringUtils.hasText(subCategory)) { |
| | | return category.trim() + "-" + subCategory.trim(); |
| | | } |
| | | if (StringUtils.hasText(subCategory)) { |
| | | return subCategory.trim(); |
| | | } |
| | | if (StringUtils.hasText(category)) { |
| | | return category.trim(); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private Integer parseInteger(String value) { |
| | | if (!StringUtils.hasText(value)) { |
| | | return 0; |
| | | } |
| | | try { |
| | | return new BigDecimal(value.trim()).setScale(0, RoundingMode.HALF_UP).intValue(); |
| | | } catch (Exception e) { |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | private Map<SalesLedgerProduct, BigDecimal> allocateShippingProductLines(String orderNo, SalesShippingImportDto row, Map<String, List<SalesLedgerProduct>> productByCategory, List<SalesLedgerProduct> allProducts) { |
| | | String subCategory = StringUtils.hasText(row.getProductSubCategory()) ? row.getProductSubCategory().trim() : ""; |
| | | List<SalesLedgerProduct> candidates = productByCategory.getOrDefault(subCategory, Collections.emptyList()); |
| | | if (CollectionUtils.isEmpty(candidates)) { |
| | | candidates = allProducts; |
| | | } |
| | | BigDecimal remaining = defaultDecimal(row.getQuantity()); |
| | | Map<SalesLedgerProduct, BigDecimal> allocations = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct p : candidates) { |
| | | BigDecimal qty = defaultDecimal(p.getQuantity()); |
| | | BigDecimal shipped = defaultDecimal(p.getShippedQuantity()); |
| | | BigDecimal canShip = qty.subtract(shipped); |
| | | if (canShip.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | BigDecimal alloc = remaining.min(canShip); |
| | | if (alloc.compareTo(BigDecimal.ZERO) > 0) { |
| | | allocations.put(p, alloc); |
| | | remaining = remaining.subtract(alloc); |
| | | } |
| | | if (remaining.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return allocations; |
| | | } |
| | | } |
| | | if (remaining.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]产品[" + subCategory + "]发货数量超出剩余可发数量"); |
| | | } |
| | | return allocations; |
| | | } |
| | | |
| | | private void updateProductShipStatus(SalesLedgerProduct dbProduct) { |
| | | BigDecimal qty = defaultDecimal(dbProduct.getQuantity()); |
| | | BigDecimal shipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | if (shipped.compareTo(BigDecimal.ZERO) <= 0) { |
| | | dbProduct.setProductStockStatus(0); |
| | | return; |
| | | } |
| | | dbProduct.setProductStockStatus(shipped.compareTo(qty) >= 0 ? 2 : 1); |
| | | } |
| | | |
| | | private void updateProductStockStatus(SalesLedgerProduct dbProduct) { |
| | | BigDecimal qty = defaultDecimal(dbProduct.getQuantity()); |
| | | BigDecimal stocked = defaultDecimal(dbProduct.getStockedQuantity()); |
| | | if (stocked.compareTo(BigDecimal.ZERO) <= 0) { |
| | | dbProduct.setProductStockStatus(0); |
| | | return; |
| | | } |
| | | dbProduct.setProductStockStatus(stocked.compareTo(qty) >= 0 ? 2 : 1); |
| | | } |
| | | |
| | | private String buildShippingRowKey(Long ledgerId, SalesShippingImportDto row) { |
| | | String shippingNo = StringUtils.hasText(row.getShippingNo()) ? row.getShippingNo().trim() : ""; |
| | | String dateStr = row.getReportDate() == null ? "" : String.valueOf(row.getReportDate().getTime()); |
| | | String subCategory = StringUtils.hasText(row.getProductSubCategory()) ? row.getProductSubCategory().trim() : ""; |
| | | return ledgerId + "|" + subCategory + "|" + shippingNo + "|" + dateStr + "|" + defaultDecimal(row.getQuantity()); |
| | | } |
| | | } |