| | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
| | | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; |
| | | |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | |
| | | 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.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.exception.ServiceException; |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.EnumUtil; |
| | |
| | | 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.production.pojo.ProcessRoute; |
| | | import com.ruoyi.production.pojo.ProcessRouteItem; |
| | | import com.ruoyi.production.service.ProductionProductMainService; |
| | | import com.ruoyi.project.system.domain.SysDept; |
| | | |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | |
| | | import com.ruoyi.sales.dto.*; |
| | | import com.ruoyi.sales.mapper.*; |
| | | import com.ruoyi.sales.pojo.*; |
| | | import com.ruoyi.sales.service.ISalesLedgerProcessRouteService; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductProcessBindService; |
| | | 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 ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService; |
| | | |
| | | private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService; |
| | | |
| | | private final StockInventoryService stockInventoryService; |
| | | private final StockInRecordMapper stockInRecordMapper; |
| | | private final StockOutRecordMapper stockOutRecordMapper; |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockOutRecordService stockOutRecordService; |
| | | |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | | @Value("${file.upload-dir}") |
| | |
| | | ; |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | private final ICustomerRegionsService customerRegionsService; |
| | | |
| | | @Override |
| | | public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) { |
| | |
| | | productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()); |
| | | productWrapper.eq(SalesLedgerProduct::getType, 1); |
| | | 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()); |
| | | if (CollectionUtils.isNotEmpty(productModelIds)) { |
| | | List<ProductModel> productModels = productModelMapper.selectBatchIds(productModelIds); |
| | | if (CollectionUtils.isNotEmpty(productModels)) { |
| | | productModelMap = productModels.stream().collect(Collectors.toMap(ProductModel::getId, Function.identity())); |
| | | } |
| | | } |
| | | } |
| | | for (SalesLedgerProduct product : products) { |
| | | product.setOriginalNoInvoiceNum(product.getNoInvoiceNum()); |
| | | // 提供临时未开票数,未开票金额供前段计算 |
| | |
| | | List<SalesLedgerProductProcess> processList = salesLedgerProductProcessService.listByIds(processIds); |
| | | processList.forEach(p -> p.setQuantity(processQuantityMap.get(p.getId()))); |
| | | product.setSalesProductProcessList(processList); |
| | | } |
| | | ProductModel productModel = productModelMap.get(product.getProductModelId()); |
| | | if (productModel != null) { |
| | | product.setThickness(productModel.getThickness()); |
| | | } |
| | | if (product.getWidth() != null && product.getHeight() != null) { |
| | | BigDecimal pieceArea = product.getWidth().multiply(product.getHeight()).divide(new BigDecimal(1000000), 2, RoundingMode.HALF_UP); |
| | | if (product.getActualPieceArea() == null) { |
| | | product.setActualPieceArea(pieceArea); |
| | | } |
| | | BigDecimal quantity = product.getQuantity() == null ? BigDecimal.ZERO : product.getQuantity(); |
| | | if (product.getActualTotalArea() == null) { |
| | | product.setActualTotalArea(pieceArea.multiply(quantity).setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | @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<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getModel, |
| | | // salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getSpecificationModel).collect(Collectors.toList()))); |
| | | // // 产品大类数据 |
| | | // List<Product> productList = productMapper.selectList(new LambdaQueryWrapper<Product>().in(Product::getProductName, |
| | | // salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getProductCategory).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) { |
| | | continue; |
| | | } |
| | | 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 RuntimeException("录入人:" + 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)); |
| | | salesLedgerMapper.insert(salesLedger); |
| | | |
| | | |
| | | for (SalesLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { |
| | | SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct); |
| | | 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.setProductId(productList.stream() |
| | | // .filter(product -> product.getProductName().equals(salesLedgerProduct.getProductCategory())) |
| | | // .findFirst() |
| | | // .map(Product::getId) |
| | | // .orElse(null)); |
| | | // salesLedgerProduct.setProductModelId(productModels.stream() |
| | | // .filter(productModel -> productModel.getModel().equals(salesLedgerProduct.getSpecificationModel())) |
| | | // .findFirst() |
| | | // .map(ProductModel::getId) |
| | | // .orElse(null)); |
| | | salesLedgerProduct.setRegister(loginUser.getNickName()); |
| | | salesLedgerProduct.setRegisterDate(LocalDateTime.now()); |
| | | salesLedgerProduct.setApproveStatus(0); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | |
| | | return AjaxResult.success("导入成功"); |
| | | 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) { |
| | | e.printStackTrace(); |
| | | log.error("销售台账导入失败:解析Excel异常", e); |
| | | throw new ServiceException("导入失败:解析Excel异常"); |
| | | } |
| | | return AjaxResult.success("导入失败"); |
| | | |
| | | 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); |
| | | } |
| | | salesLedgerProduct.setActualPieceArea(actualPieceArea); |
| | | salesLedgerProduct.setActualTotalArea(actualPieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP)); |
| | | |
| | | BigDecimal settlePieceArea = salesLedgerProduct.getSettlePieceArea() == null |
| | | ? actualPieceArea |
| | | : salesLedgerProduct.getSettlePieceArea(); |
| | | salesLedgerProduct.setSettlePieceArea(settlePieceArea); |
| | | salesLedgerProduct.setSettleTotalArea(settlePieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP)); |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 含税总价 = 单价 * 结算面积 * 数量 + 额外加工金额 * 数量 |
| | | 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); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | if (!processList.isEmpty()) { |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(processList, salesLedgerProduct.getId()); |
| | | } |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | contractAmount = contractAmount.add(taxInclusiveTotalPrice); |
| | | } |
| | | salesLedger.setContractAmount(contractAmount); |
| | | salesLedgerMapper.updateById(salesLedger); |
| | | } |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | return salesLedgerDtoIPage; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void saleProcessBind(SalesLedgerProcessRoute salesLedgerProcessRoute) { |
| | | if (salesLedgerProcessRoute == null) { |
| | | throw new ServiceException("绑定失败,数据不能为空"); |
| | | } |
| | | |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRoute.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("绑定失败,销售订单不存在"); |
| | | } |
| | | ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRoute.getProcessRouteId()); |
| | | if (processRoute == null) { |
| | | throw new ServiceException("绑定失败,工艺路线不存在"); |
| | | } |
| | | // 清除已绑定的数据 |
| | | salesLedgerProcessRouteService.remove(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId())); |
| | | |
| | | // 将数据迁移到sales_ledger_process_route |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId())); |
| | | SalesLedgerProcessRoute ledgerProcessRoute; |
| | | List<SalesLedgerProcessRoute> salesLedgerProcessRouteList = new ArrayList<>(); |
| | | for (ProcessRouteItem routeItem : routeItems) { |
| | | ledgerProcessRoute = new SalesLedgerProcessRoute(); |
| | | ledgerProcessRoute.setProcessRouteId(processRoute.getId()); |
| | | ledgerProcessRoute.setSalesLedgerId(salesLedger.getId()); |
| | | ledgerProcessRoute.setProcessRouteItemId(routeItem.getId()); |
| | | ledgerProcessRoute.setDragSort(routeItem.getDragSort()); |
| | | salesLedgerProcessRouteList.add(ledgerProcessRoute); |
| | | } |
| | | salesLedgerProcessRouteService.saveBatch(salesLedgerProcessRouteList); |
| | | } |
| | | |
| | | /** |
| | |
| | | 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 (salesLedger.getId() == null) { |
| | | String contractNo = generateSalesContractNo(); |
| | | salesLedger.setSalesContractNo(contractNo); |
| | | salesLedger.setDeliveryStatus(1); |
| | | salesLedger.setStockStatus(0); |
| | | salesLedgerMapper.insert(salesLedger); |
| | | } else { |
| | | if (salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("订单已发货,禁止编辑"); |
| | | } |
| | | salesLedgerMapper.updateById(salesLedger); |
| | | } |
| | | |
| | |
| | | if (!updateList.isEmpty()) { |
| | | for (SalesLedgerProduct product : updateList) { |
| | | product.setType(type.getCode()); |
| | | product.setProductStockStatus(0); |
| | | salesLedgerProductMapper.updateById(product); |
| | | // 清空销售产品绑定的加工 |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(product.getSalesProductProcessList(), product.getId()); |
| | |
| | | salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProduct.setProductStockStatus(0); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | // 绑定产品额外加工 |
| | | // 清空销售产品绑定的加工 |
| | | salesLedgerProductProcessBindService.updateProductProcessBind(salesLedgerProduct.getSalesProductProcessList(), salesLedgerProduct.getId()); |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | // salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | if (!redisTemplate.hasKey(lockKey)) { |
| | | if (Boolean.FALSE.equals(redisTemplate.hasKey(lockKey))) { |
| | | throw new RuntimeException("获取合同编号生成锁失败:超时"); |
| | | } |
| | | |
| | | // 2. 查询当天/公司已存在的序列号(与原逻辑一致) |
| | | Long tenantId = SecurityUtils.getLoginUser().getTenantId(); |
| | | if (null != tenantId) { |
| | | //获取公司编号 |
| | | SysDept sysDept = sysDeptMapper.selectDeptById(tenantId.longValue()); |
| | | if (!ObjectUtils.isEmpty(sysDept)) { |
| | | datePart = (StringUtils.isEmpty(sysDept.getDeptNick()) ? "" : sysDept.getDeptNick()) + datePart; |
| | | } |
| | | } |
| | | // Long tenantId = SecurityUtils.getLoginUser().getTenantId(); |
| | | // if (null != tenantId) { |
| | | // //获取公司编号 |
| | | // SysDept sysDept = sysDeptMapper.selectDeptById(tenantId); |
| | | // if (!ObjectUtils.isEmpty(sysDept)) { |
| | | // datePart = (StringUtils.isEmpty(sysDept.getDeptNick()) ? "" : sysDept.getDeptNick()) + datePart; |
| | | // } |
| | | // } |
| | | datePart = "D" + datePart; |
| | | List<Integer> existingSequences = salesLedgerMapper.selectSequencesByDate(datePart); |
| | | int nextSequence = findFirstMissingSequence(existingSequences); |
| | | |
| | |
| | | lockValue |
| | | ); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public SalesLedgerProcessRouteDto salesProcess(Long salesLedgerId) { |
| | | SalesLedgerProcessRouteDto dto = new SalesLedgerProcessRouteDto(); |
| | | List<SalesLedgerProcessRoute> list = baseMapper.selectSalesProcess(salesLedgerId); |
| | | if (CollectionUtils.isNotEmpty(list)) { |
| | | Long processRouteId = list.get(0).getProcessRouteId(); |
| | | ProcessRoute processRoute = processRouteMapper.selectById(processRouteId); |
| | | if (processRoute != null) { |
| | | dto.setRouteId(processRoute.getId()); |
| | | dto.setRouteName(processRoute.getProcessRouteName()); |
| | | } |
| | | } else { |
| | | // 要是list查询为空的话,就查询默认的工艺路线返回 |
| | | ProcessRoute defaultRoute = processRouteMapper.selectOne(new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("limit 1")); |
| | | if (defaultRoute != null) { |
| | | dto.setRouteId(defaultRoute.getId()); |
| | | dto.setRouteName(defaultRoute.getProcessRouteName()); |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, defaultRoute.getId()).orderByAsc(ProcessRouteItem::getDragSort)); |
| | | list = routeItems.stream().map(item -> { |
| | | SalesLedgerProcessRoute salesLedgerProcessRoute = new SalesLedgerProcessRoute(); |
| | | salesLedgerProcessRoute.setProcessRouteId(defaultRoute.getId()); |
| | | salesLedgerProcessRoute.setSalesLedgerId(salesLedgerId); |
| | | salesLedgerProcessRoute.setProcessRouteItemId(item.getId()); |
| | | salesLedgerProcessRoute.setProcessName(item.getProcessName()); |
| | | salesLedgerProcessRoute.setDragSort(item.getDragSort()); |
| | | return salesLedgerProcessRoute; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | } |
| | | dto.setList(list); |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public SalesProcessCardDto processCard(Long salesLedgerId) { |
| | | if (salesLedgerId == null) { |
| | | throw new ServiceException("流程卡打印失败,打印销售订单不能为空"); |
| | | } |
| | | // 查询销售订单 |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerId); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("流程卡打印失败,销售订单不存在"); |
| | | } |
| | | |
| | | SalesProcessCardDto dto = new SalesProcessCardDto(); |
| | | dto.setSalesContractNo(salesLedger.getSalesContractNo()); |
| | | dto.setCustomerName(salesLedger.getCustomerName()); |
| | | dto.setDeliveryDate(salesLedger.getDeliveryDate()); |
| | | dto.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); |
| | | dto.setRegisterDate(LocalDateTime.now()); |
| | | dto.setOrderProcessRequirement(salesLedger.getRemarks()); |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | BigDecimal totalQuantity = BigDecimal.ZERO; |
| | | BigDecimal totalArea = BigDecimal.ZERO; |
| | | List<SalesProcessCardDto.ProcessCardItemDto> itemDtos = new ArrayList<>(); |
| | | |
| | | for (SalesLedgerProduct p : products) { |
| | | SalesProcessCardDto.ProcessCardItemDto itemDto = new SalesProcessCardDto.ProcessCardItemDto(); |
| | | itemDto.setFloorCode(p.getFloorCode()); |
| | | // 组装产品描述:大类 + (规格) |
| | | 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()); |
| | | itemDto.setQuantity(p.getQuantity()); |
| | | |
| | | // 面积计算(平米) |
| | | BigDecimal area = p.getActualPieceArea() != null ? p.getActualPieceArea() : p.getSettlePieceArea(); |
| | | if (area == null && p.getWidth() != null && p.getHeight() != null) { |
| | | area = p.getWidth().multiply(p.getHeight()).divide(new BigDecimal(1000000), 2, RoundingMode.HALF_UP); |
| | | } |
| | | itemDto.setArea(area); |
| | | itemDto.setProcessRequirement(p.getProcessRequirement()); |
| | | |
| | | BigDecimal qty = p.getQuantity() != null ? p.getQuantity() : BigDecimal.ZERO; |
| | | totalQuantity = totalQuantity.add(qty); |
| | | if (area != null) { |
| | | totalArea = totalArea.add(area.multiply(qty)); |
| | | } |
| | | |
| | | itemDtos.add(itemDto); |
| | | } |
| | | dto.setItems(itemDtos); |
| | | dto.setTotalQuantity(totalQuantity); |
| | | dto.setTotalArea(totalArea.setScale(2, RoundingMode.HALF_UP)); |
| | | |
| | | // 工艺路线 |
| | | 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)); |
| | | for (ProcessRouteItem i : routeItems) { |
| | | SalesProcessCardDto.ProcessNodeDto node = new SalesProcessCardDto.ProcessNodeDto(); |
| | | node.setProcessRouteItemId(i.getId()); |
| | | node.setProcessRouteItemName(i.getProcessName()); |
| | | node.setDragSort(i.getDragSort()); |
| | | nodeDtos.add(node); |
| | | } |
| | | } |
| | | } else { |
| | | // 使用自定义路线绑定的节点 |
| | | 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)); |
| | | |
| | | for (SalesLedgerProcessRoute r : salesLedgerProcessRoutes) { |
| | | ProcessRouteItem pi = itemMap.get(r.getProcessRouteItemId()); |
| | | if (pi != null) { |
| | | SalesProcessCardDto.ProcessNodeDto node = new SalesProcessCardDto.ProcessNodeDto(); |
| | | node.setProcessRouteItemId(pi.getId()); |
| | | node.setProcessRouteItemName(pi.getProcessName()); |
| | | node.setDragSort(r.getDragSort() != null ? r.getDragSort() : pi.getDragSort()); |
| | | node.setRemark(r.getRemark()); |
| | | nodeDtos.add(node); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!nodeDtos.isEmpty()) { |
| | | // dragSort 进行升序排序 |
| | | nodeDtos.sort(Comparator.comparing( |
| | | SalesProcessCardDto.ProcessNodeDto::getDragSort, |
| | | Comparator.nullsLast(Comparator.naturalOrder()) |
| | | )); |
| | | // 重新生成排序后的路径名称列表 |
| | | List<String> sortedPathNames = nodeDtos.stream() |
| | | .map(SalesProcessCardDto.ProcessNodeDto::getProcessRouteItemName) |
| | | .collect(Collectors.toList()); |
| | | // 拼接字符串 |
| | | dto.setProcessPathDisplay(String.join(" -> ", sortedPathNames)); |
| | | // 设置顶层节点的工艺路线 |
| | | dto.setRouteNodes(nodeDtos); |
| | | } |
| | | |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public SalesOrdersDto salesOrders(Long salesLedgerId) { |
| | | if (salesLedgerId == null) { |
| | | throw new ServiceException("打印销售订单失败,销售订单ID不能为空"); |
| | | } |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerId); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("打印销售订单失败,销售订单不存在"); |
| | | } |
| | | |
| | | SalesOrdersDto dto = new SalesOrdersDto(); |
| | | dto.setSalesContractNo(salesLedger.getSalesContractNo()); |
| | | dto.setCustomerName(salesLedger.getCustomerName()); |
| | | dto.setProjectName(salesLedger.getProjectName()); |
| | | dto.setSalesman(salesLedger.getSalesman()); |
| | | dto.setExecutionDate(salesLedger.getExecutionDate() != null ? salesLedger.getExecutionDate().atStartOfDay() : null); |
| | | dto.setDeliveryDate(salesLedger.getDeliveryDate()); |
| | | dto.setRemakes(salesLedger.getRemarks()); |
| | | dto.setCompanyName("鹤壁天沐钢化玻璃厂"); |
| | | |
| | | // 送货地址 |
| | | if (salesLedger.getCustomerId() != null) { |
| | | Customer customer = customerMapper.selectById(salesLedger.getCustomerId()); |
| | | if (customer != null) { |
| | | StringBuilder address = new StringBuilder(); |
| | | if (customer.getRegionsId() != null) { |
| | | CustomerRegions regions = customerRegionsService.getById(customer.getRegionsId()); |
| | | if (regions != null) { |
| | | address.append(regions.getRegionsName()); |
| | | } |
| | | } |
| | | if (StringUtils.isNotEmpty(customer.getCompanyAddress())) { |
| | | address.append(customer.getCompanyAddress()); |
| | | } |
| | | dto.setCompanyAddress(address.toString()); |
| | | } |
| | | } |
| | | |
| | | // 制单员 |
| | | if (StringUtils.isNotEmpty(salesLedger.getEntryPerson())) { |
| | | try { |
| | | SysUser user = sysUserMapper.selectUserById(Long.parseLong(salesLedger.getEntryPerson())); |
| | | if (user != null) { |
| | | dto.setOrderMaker(user.getNickName()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取制单员信息失败: {}", e.getMessage()); |
| | | } |
| | | } |
| | | // 制单日期 (底部) |
| | | dto.setOrderMakerDate(salesLedger.getExecutionDate() != null ? salesLedger.getExecutionDate().atStartOfDay() : null); |
| | | |
| | | // 打印信息 |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | if (loginUser != null && loginUser.getUser() != null) { |
| | | dto.setPrintPeople(loginUser.getUser().getNickName()); |
| | | } |
| | | dto.setPrintTime(LocalDateTime.now()); |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | SalesLedgerProduct firstProduct = products.get(0); |
| | | dto.setProductName(firstProduct.getProductCategory() != null ? firstProduct.getProductCategory() : ""); |
| | | } |
| | | |
| | | List<SalesOrdersDto.SalesOrderItemDto> itemDtos = new ArrayList<>(); |
| | | BigDecimal subtotalQuantity = BigDecimal.ZERO; |
| | | BigDecimal subtotalArea = BigDecimal.ZERO; |
| | | BigDecimal subtotalAmount = BigDecimal.ZERO; |
| | | |
| | | 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() : ""); |
| | | itemDto.setProductDescription(desc.trim()); |
| | | itemDto.setWidth(p.getWidth()); |
| | | itemDto.setHeight(p.getHeight()); |
| | | itemDto.setQuantity(p.getQuantity()); |
| | | |
| | | // 面积计算 |
| | | 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); |
| | | } |
| | | itemDto.setArea(area); |
| | | itemDto.setUnitPrice(p.getTaxInclusiveUnitPrice()); |
| | | itemDto.setAmount(p.getTaxInclusiveTotalPrice()); |
| | | itemDto.setRemark(p.getRemark()); |
| | | itemDto.setProcessRequirement(p.getProcessRequirement()); |
| | | |
| | | subtotalQuantity = subtotalQuantity.add(p.getQuantity() != null ? p.getQuantity() : BigDecimal.ZERO); |
| | | subtotalArea = subtotalArea.add(area != null ? area : BigDecimal.ZERO); |
| | | subtotalAmount = subtotalAmount.add(p.getTaxInclusiveTotalPrice() != null ? p.getTaxInclusiveTotalPrice() : BigDecimal.ZERO); |
| | | |
| | | itemDtos.add(itemDto); |
| | | } |
| | | dto.setItems(itemDtos); |
| | | dto.setSubtotalQuantity(subtotalQuantity); |
| | | dto.setSubtotalArea(subtotalArea.setScale(2, RoundingMode.HALF_UP)); |
| | | dto.setSubtotalAmount(subtotalAmount); |
| | | |
| | | // 处理其他费用 |
| | | 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)); |
| | | |
| | | if (CollectionUtils.isNotEmpty(binds)) { |
| | | 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); |
| | | |
| | | List<SalesOrdersDto.OtherFeeDto> otherFeeDtos = new ArrayList<>(); |
| | | |
| | | for (SalesLedgerProductProcess proc : processes) { |
| | | SalesOrdersDto.OtherFeeDto feeDto = new SalesOrdersDto.OtherFeeDto(); |
| | | feeDto.setFeeName(proc.getProcessName()); |
| | | feeDto.setUnitPrice(proc.getUnitPrice()); |
| | | Integer qty = processQuantityMap.get(proc.getId()); |
| | | feeDto.setQuantity(new BigDecimal(qty != null ? qty : 0)); |
| | | BigDecimal amount = proc.getUnitPrice() != null ? proc.getUnitPrice().multiply(feeDto.getQuantity()) : BigDecimal.ZERO; |
| | | feeDto.setAmount(amount); |
| | | otherFeeDtos.add(feeDto); |
| | | otherFeesTotal = otherFeesTotal.add(amount); |
| | | } |
| | | dto.setOtherFees(otherFeeDtos); |
| | | } |
| | | } |
| | | |
| | | dto.setTotalQuantity(subtotalQuantity); |
| | | dto.setTotalArea(dto.getSubtotalArea()); |
| | | dto.setTotalAmount(subtotalAmount.add(otherFeesTotal)); |
| | | dto.setTotalAmountDisplay(dto.getTotalAmount().setScale(2, RoundingMode.HALF_UP).toString() + "元"); |
| | | |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public SalesInvoicesDto salesInvoices(List<Long> salesLedgerIds) { |
| | | if (CollectionUtils.isEmpty(salesLedgerIds)) { |
| | | throw new ServiceException("销售发货单打印失败,销售订单不能为空"); |
| | | } |
| | | |
| | | List<SalesLedger> ledgers = salesLedgerMapper.selectBatchIds(salesLedgerIds); |
| | | if (CollectionUtils.isEmpty(ledgers)) { |
| | | throw new ServiceException("销售发货单打印失败,未找到对应台账记录"); |
| | | } |
| | | |
| | | Long customerId = ledgers.get(0).getCustomerId(); |
| | | for (SalesLedger ledger : ledgers) { |
| | | if (!Objects.equals(customerId, ledger.getCustomerId())) { |
| | | throw new ServiceException("销售发货单合并打印只能是同一个客户"); |
| | | } |
| | | } |
| | | |
| | | SalesInvoicesDto dto = new SalesInvoicesDto(); |
| | | |
| | | Customer customer = customerMapper.selectById(customerId); |
| | | if (customer != null) { |
| | | dto.setCustomerName(customer.getCustomerName()); |
| | | dto.setContactPerson(customer.getContactPerson()); |
| | | dto.setContactPhone(customer.getContactPhone()); |
| | | |
| | | StringBuilder address = new StringBuilder(); |
| | | if (customer.getRegionsId() != null) { |
| | | CustomerRegions regions = customerRegionsService.getById(customer.getRegionsId()); |
| | | if (regions != null) { |
| | | address.append(regions.getRegionsName()); |
| | | } |
| | | } |
| | | if (StringUtils.isNotEmpty(customer.getCompanyAddress())) { |
| | | address.append(customer.getCompanyAddress()); |
| | | } |
| | | dto.setCompanyAddress(address.toString()); |
| | | } |
| | | |
| | | // 发货单号 (XF + 日期 + 序列) |
| | | String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")); |
| | | String redisKey = "sales:delivery:seq:" + dateStr; |
| | | Long seq = redisTemplate.opsForValue().increment(redisKey); |
| | | if (seq != null && seq == 1) { |
| | | redisTemplate.expire(redisKey, 48, TimeUnit.HOURS); |
| | | } |
| | | dto.setDeliveryNo("XF" + dateStr + String.format("%03d", seq != null ? seq : 1)); |
| | | |
| | | // 对方单号 |
| | | // dto.setExternalOrderNo(ledgers.get(0).getCustomerContractNo()); |
| | | |
| | | // 查询所有产品 |
| | | List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds)); |
| | | |
| | | 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); |
| | | } |
| | | |
| | | 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(); |
| | | |
| | | SalesInvoicesDto.InvoiceOrderGroupDto group = new SalesInvoicesDto.InvoiceOrderGroupDto(); |
| | | group.setSalesContractNo(orderNo); |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | group.setProductName(products.get(0).getProductCategory()); |
| | | } |
| | | |
| | | List<SalesInvoicesDto.InvoiceItemDto> itemDtos = new ArrayList<>(); |
| | | 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()); |
| | | |
| | | // 面积 |
| | | 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()); |
| | | |
| | | itemDtos.add(item); |
| | | groupQty = groupQty.add(p.getQuantity() != null ? p.getQuantity() : BigDecimal.ZERO); |
| | | groupArea = groupArea.add(area != null ? area : BigDecimal.ZERO); |
| | | } |
| | | |
| | | group.setItems(itemDtos); |
| | | group.setGroupTotalQuantity(groupQty); |
| | | group.setGroupTotalArea(groupArea.setScale(2, RoundingMode.HALF_UP)); |
| | | groups.add(group); |
| | | |
| | | totalQty = totalQty.add(groupQty); |
| | | totalArea = totalArea.add(groupArea); |
| | | } |
| | | dto.setGroups(groups); |
| | | dto.setTotalQuantity(totalQty); |
| | | dto.setTotalArea(totalArea.setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | if (loginUser != null && loginUser.getUser() != null) { |
| | | dto.setOrderMaker(loginUser.getUser().getNickName()); |
| | | } |
| | | dto.setExecutionDate(LocalDateTime.now()); |
| | | |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public List<SalesLabelDto> salesLabel(Long salesLedgerId) { |
| | | if (salesLedgerId == null) { |
| | | throw new ServiceException("打印标签失败,数据不能为空"); |
| | | } |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerId); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("打印失败,销售订单不存在"); |
| | | } |
| | | |
| | | // 查询产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)); |
| | | |
| | | // 查询客户地址 |
| | | String fullAddress = ""; |
| | | if (salesLedger.getCustomerId() != null) { |
| | | Customer customer = customerMapper.selectById(salesLedger.getCustomerId()); |
| | | if (customer != null) { |
| | | StringBuilder addressSb = new StringBuilder(); |
| | | if (customer.getRegionsId() != null) { |
| | | CustomerRegions regions = customerRegionsService.getById(customer.getRegionsId()); |
| | | if (regions != null) { |
| | | addressSb.append(regions.getRegionsName()); |
| | | } |
| | | } |
| | | if (StringUtils.isNotEmpty(customer.getCompanyAddress())) { |
| | | addressSb.append(customer.getCompanyAddress()); |
| | | } |
| | | fullAddress = addressSb.toString(); |
| | | } |
| | | } |
| | | |
| | | List<SalesLabelDto> list = new ArrayList<>(); |
| | | if (CollectionUtils.isNotEmpty(products)) { |
| | | for (SalesLedgerProduct p : products) { |
| | | SalesLabelDto dto = new SalesLabelDto(); |
| | | dto.setCustomerName(salesLedger.getCustomerName()); |
| | | dto.setSalesContractNo(salesLedger.getSalesContractNo()); |
| | | dto.setProductName(p.getProductCategory()); |
| | | |
| | | // 宽*高=数量 |
| | | 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); |
| | | |
| | | // 客户地址 + 楼层编号 |
| | | dto.setFloorCode(fullAddress + (StringUtils.isNotEmpty(p.getFloorCode()) ? " " + p.getFloorCode() : "")); |
| | | list.add(dto); |
| | | } |
| | | } |
| | | |
| | | return list; |
| | | } |
| | | |
| | | private int findFirstMissingSequence(List<Integer> sequences) { |
| | |
| | | return totalAmount; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void salesStock(SalesProductStockDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new NullPointerException("入库失败,请选择需要入库的销售订单"); |
| | | } |
| | | // 查询销售订单是否存在 |
| | | SalesLedger ledger = baseMapper.selectById(dto.getSalesLedgerId()); |
| | | if (ledger == null) { |
| | | throw new ServiceException("入库失败,销售订单不存在"); |
| | | } |
| | | if (ledger.getStockStatus() == null) { |
| | | 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().in(SalesLedgerProduct::getId, products)); |
| | | if (salesLedgerProducts == null || salesLedgerProducts.isEmpty()) { |
| | | throw new ServiceException("入库失败,未查询到该销售订单的销售产品"); |
| | | } |
| | | for (SalesLedgerProduct product : salesLedgerProducts) { |
| | | if (product.getProductModelId() == null) { |
| | | continue; |
| | | } |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordId(product.getId()); |
| | | stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode()); |
| | | stockInventoryDto.setQualitity(product.getQuantity()); |
| | | stockInventoryDto.setProductModelId(product.getProductModelId()); |
| | | stockInventoryDto.setSalesLedgerId(ledger.getId()); |
| | | stockInventoryDto.setSalesLedgerProductId(product.getId()); |
| | | stockInventoryService.addstockInventory(stockInventoryDto); |
| | | } |
| | | // 按销售订单产品入库情况更新主单入库状态:1-部分入库,2-已入库 |
| | | List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId())); |
| | | boolean hasStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().anyMatch(item -> Objects.equals(item.getProductStockStatus(), 1)); |
| | | boolean allStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().allMatch(item -> Objects.equals(item.getProductStockStatus(), 1)); |
| | | ledger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0)); |
| | | baseMapper.updateById(ledger); |
| | | } |
| | | } |