| | |
| | | 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; |
| | |
| | | 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 SysDeptMapper sysDeptMapper; |
| | |
| | | product.setActualTotalArea(pieceArea.multiply(quantity).setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | product.fillRemainingQuantity(); |
| | | } |
| | | |
| | | // 3.查询上传文件 |
| | |
| | | |
| | | @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") |
| | | 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) |
| | | ); |
| | | if (process != null) { |
| | | SalesLedgerProductProcess p = new SalesLedgerProductProcess(); |
| | | p.setId(process.getId()); |
| | | p.setQuantity(quantity.intValue()); |
| | | processList.add(p); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("解析额外加工数量失败: {}", qtyStr); |
| | | } |
| | | } 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; |
| | | } |
| | | |
| | |
| | | .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()); |
| | |
| | | if (!updateList.isEmpty()) { |
| | | for (SalesLedgerProduct product : updateList) { |
| | | product.setType(type.getCode()); |
| | | 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()); |
| | | salesLedgerProduct.setProductStockStatus(0); |
| | | salesLedgerProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | // 绑定产品额外加工 |
| | | // 清空销售产品绑定的加工 |
| | |
| | | List<SalesProcessCardDto.ProcessNodeDto> nodeDtos = new ArrayList<>(); |
| | | |
| | | if (CollectionUtils.isEmpty(salesLedgerProcessRoutes)) { |
| | | // 无自定义路线,取默认路线 |
| | | ProcessRoute defaultRoute = processRouteMapper.selectOne( |
| | | // 无自定义路线:先查询默认工艺路线;若无默认,获取创建时间最近的一条 |
| | | ProcessRoute fallbackRoute = processRouteMapper.selectOne( |
| | | new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("LIMIT 1")); |
| | | if (defaultRoute != null) { |
| | | 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, defaultRoute.getId()) |
| | | .eq(ProcessRouteItem::getRouteId, fallbackRoute.getId()) |
| | | .orderByAsc(ProcessRouteItem::getDragSort)); |
| | | for (ProcessRouteItem i : routeItems) { |
| | | SalesProcessCardDto.ProcessNodeDto node = new SalesProcessCardDto.ProcessNodeDto(); |
| | |
| | | |
| | | @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() == 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("入库失败,未查询到该销售订单的销售产品"); |
| | | } |
| | | 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); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal inboundThisLine = entry.getValue(); |
| | | if (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); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : inboundQtyByLineId.entrySet()) { |
| | | Long salesLedgerProductId = entry.getKey(); |
| | | BigDecimal inboundThisLine = entry.getValue(); |
| | | if (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); |
| | | } |
| | | } |
| | | |
| | | @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); |
| | | } |
| | | } |
| | | } |