| | |
| | | package com.ruoyi.sales.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | 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.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.node.ObjectNode; |
| | | import com.ruoyi.account.service.AccountIncomeService; |
| | | import com.ruoyi.approve.pojo.ApproveProcess; |
| | | import com.ruoyi.approve.service.IApproveProcessService; |
| | | import com.ruoyi.approve.vo.ApproveProcessVO; |
| | | import com.ruoyi.approve.pojo.ApproveProcess; |
| | | import com.ruoyi.common.enums.ApproveTypeEnum; |
| | | import com.ruoyi.basic.mapper.CustomerMapper; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.basic.service.ICustomerRegionsService; |
| | | import com.ruoyi.common.enums.FileNameType; |
| | | import com.ruoyi.common.enums.SaleEnum; |
| | | import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.StockOutUnQualifiedRecordTypeEnum; |
| | | import com.ruoyi.common.enums.*; |
| | | 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.SecurityUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.*; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.other.mapper.TempFileMapper; |
| | | import com.ruoyi.other.pojo.TempFile; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | 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.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.quality.mapper.QualityInspectParamMapper; |
| | | import com.ruoyi.quality.mapper.QualityTestStandardMapper; |
| | | import com.ruoyi.quality.mapper.QualityTestStandardParamMapper; |
| | | import com.ruoyi.quality.pojo.QualityInspect; |
| | | import com.ruoyi.quality.pojo.QualityInspectParam; |
| | | import com.ruoyi.quality.pojo.QualityTestStandard; |
| | | import com.ruoyi.quality.pojo.QualityTestStandardParam; |
| | | 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.ISalesLedgerProcessRouteRecordService; |
| | | 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.StockInventoryMapper; |
| | | import com.ruoyi.stock.mapper.StockOutRecordMapper; |
| | | import com.ruoyi.stock.pojo.StockInRecord; |
| | | import com.ruoyi.stock.pojo.StockOutRecord; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.lang.reflect.Field; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.net.URLEncoder; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | | import java.nio.file.StandardCopyOption; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.time.YearMonth; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | |
| | | private final ProductionProductOutputMapper productionProductOutputMapper; |
| | | private final ProductionProductInputMapper productionProductInputMapper; |
| | | private final QualityInspectMapper qualityInspectMapper; |
| | | private final QualityInspectParamMapper qualityInspectParamMapper; |
| | | private final QualityTestStandardMapper qualityTestStandardMapper; |
| | | private final QualityTestStandardParamMapper qualityTestStandardParamMapper; |
| | | private final RedisTemplate<String, String> redisTemplate; |
| | | |
| | | private final ISalesLedgerProductProcessService salesLedgerProductProcessService; |
| | |
| | | private final ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService; |
| | | |
| | | private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService; |
| | | private final ISalesLedgerProcessRouteRecordService salesLedgerProcessRouteRecordService; |
| | | |
| | | private final StockInventoryService stockInventoryService; |
| | | private final StockInRecordMapper stockInRecordMapper; |
| | | private final StockOutRecordMapper stockOutRecordMapper; |
| | | private final StockInventoryMapper stockInventoryMapper; |
| | | private final StockInRecordService stockInRecordService; |
| | | private final StockOutRecordService stockOutRecordService; |
| | | private final StockUtils stockUtils; |
| | | private final ShipmentApprovalMapper shipmentApprovalMapper; |
| | | |
| | | @Autowired |
| | | private IApproveProcessService approveProcessService; |
| | | |
| | |
| | | public List getTopFiveList() { |
| | | // 查询原始数据 |
| | | LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery(); |
| | | queryWrapper.select(SalesLedger::getCustomerId, SalesLedger::getCustomerName, SalesLedger::getContractAmount).orderByDesc(SalesLedger::getContractAmount); |
| | | queryWrapper.select(SalesLedger::getCustomerId, SalesLedger::getCustomerName, SalesLedger::getContractAmount) |
| | | .orderByDesc(SalesLedger::getContractAmount) |
| | | .ne(SalesLedger::getReviewStatus, 2); // 排除反审核数据 |
| | | List<SalesLedger> records = salesLedgerMapper.selectList(queryWrapper); |
| | | |
| | | // 按客户ID分组并聚合金额 |
| | |
| | | |
| | | @Override |
| | | public IPage<SalesLedger> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) { |
| | | // 添加 reviewStatus 的筛选条件 |
| | | IPage<SalesLedger> iPage = salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto); |
| | | |
| | | if (CollectionUtils.isEmpty(iPage.getRecords())) { |
| | |
| | | salesLedger.setIsFh(isFh); |
| | | |
| | | salesLedger.setIsEdit(!isFh); |
| | | |
| | | // 根据 reviewStatus 控制反审相关字段的显示 |
| | | if (salesLedger.getReviewStatus() != null && salesLedger.getReviewStatus() != 2) { |
| | | // 当 reviewStatus 不为 2 时,隐藏反审时间、反审人和反审人ID |
| | | salesLedger.setCounterReviewTime(null); |
| | | salesLedger.setCounterReviewPerson(null); |
| | | salesLedger.setCounterReviewPersonId(null); |
| | | } |
| | | } |
| | | |
| | | if (salesLedgerDto.getStatus() != null && salesLedgerDto.getStatus()) { |
| | |
| | | product.setRegisterDate(LocalDateTime.now()); |
| | | // 发货信息 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerProductId, product.getId()).orderByDesc(ShippingInfo::getCreateTime).last("limit 1")); |
| | | product.setShippingCarNumber(shippingInfo.getShippingCarNumber()); |
| | | product.setShippingDate(shippingInfo.getShippingDate()); |
| | | if (shippingInfo != null) { |
| | | product.setShippingCarNumber(shippingInfo.getShippingCarNumber()); |
| | | product.setShippingDate(shippingInfo.getShippingDate()); |
| | | product.setShippingStatus(shippingInfo.getStatus()); |
| | | } |
| | | } |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void saleProcessBind(SalesLedgerProcessRoute salesLedgerProcessRoute) { |
| | | if (salesLedgerProcessRoute == null) { |
| | | public void saleProcessBind(SalesLedgerProcessRouteDto salesLedgerProcessRouteDto) { |
| | | if (salesLedgerProcessRouteDto == null) { |
| | | throw new ServiceException("绑定失败,数据不能为空"); |
| | | } |
| | | |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRoute.getSalesLedgerId()); |
| | | SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRouteDto.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | throw new ServiceException("绑定失败,销售订单不存在"); |
| | | } |
| | | ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRoute.getProcessRouteId()); |
| | | ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRouteDto.getProcessRouteId()); |
| | | if (processRoute == null) { |
| | | throw new ServiceException("绑定失败,工艺路线不存在"); |
| | | } |
| | | // 清除已绑定的数据 |
| | | salesLedgerProcessRouteService.remove(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId())); |
| | | salesLedgerProcessRouteRecordService.remove(new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>().eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedger.getId())); |
| | | |
| | | // 将数据迁移到sales_ledger_process_route |
| | | List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId())); |
| | |
| | | salesLedgerProcessRouteList.add(ledgerProcessRoute); |
| | | } |
| | | salesLedgerProcessRouteService.saveBatch(salesLedgerProcessRouteList); |
| | | |
| | | List<SalesLedgerProcessRoute> savedRoutes = salesLedgerProcessRouteService.list(new LambdaQueryWrapper<SalesLedgerProcessRoute>() |
| | | .eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId()) |
| | | .eq(SalesLedgerProcessRoute::getProcessRouteId, processRoute.getId())); |
| | | Map<Long, SalesLedgerProcessRoute> routeMap = savedRoutes.stream() |
| | | .filter(item -> item.getProcessRouteItemId() != null) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getProcessRouteItemId, item -> item, (a, b) -> a)); |
| | | |
| | | Map<Long, SalesLedgerProcessRouteRecord> inputRecordMap = new HashMap<>(); |
| | | if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteDto.getRecordList())) { |
| | | for (SalesLedgerProcessRouteRecord record : salesLedgerProcessRouteDto.getRecordList()) { |
| | | if (record != null && record.getProcessRouteItemId() != null) { |
| | | inputRecordMap.put(record.getProcessRouteItemId(), record); |
| | | } |
| | | } |
| | | } |
| | | |
| | | List<SalesLedgerProcessRouteRecord> routeRecordList = new ArrayList<>(); |
| | | for (ProcessRouteItem routeItem : routeItems) { |
| | | SalesLedgerProcessRoute route = routeMap.get(routeItem.getId()); |
| | | if (route == null || route.getId() == null) { |
| | | continue; |
| | | } |
| | | SalesLedgerProcessRouteRecord inputRecord = inputRecordMap.get(routeItem.getId()); |
| | | SalesLedgerProcessRouteRecord record = new SalesLedgerProcessRouteRecord(); |
| | | record.setSalesLedgerId(salesLedger.getId()); |
| | | record.setSalesLedgerProcessRouteId(route.getId()); |
| | | Integer isCompleted = inputRecord != null && inputRecord.getIsCompleted() != null ? inputRecord.getIsCompleted() : 0; |
| | | record.setIsCompleted(isCompleted); |
| | | record.setCompletedTime(Objects.equals(isCompleted, 1) ? LocalDateTime.now() : null); |
| | | routeRecordList.add(record); |
| | | } |
| | | salesLedgerProcessRouteRecordService.saveBatch(routeRecordList); |
| | | } |
| | | |
| | | /** |
| | |
| | | List<Long> idList = Arrays.stream(ids).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(idList)) { |
| | | return 0; |
| | | } |
| | | // 校验:已审核的订单不能删除 |
| | | List<SalesLedger> ledgers = salesLedgerMapper.selectBatchIds(idList); |
| | | for (SalesLedger ledger : ledgers) { |
| | | if (ledger.getReviewStatus() != null && ledger.getReviewStatus() == 1) { |
| | | throw new ServiceException("已审核的订单不能删除:" + ledger.getSalesContractNo()); |
| | | } |
| | | } |
| | | // 删除销售管理数据 |
| | | LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>(); |
| | |
| | | } else { |
| | | if (salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("订单已发货,禁止编辑"); |
| | | } |
| | | // 查询数据库中的原始记录用于校验 |
| | | SalesLedger existingLedger = salesLedgerMapper.selectById(salesLedger.getId()); |
| | | if (salesLedger.getReviewStatus() != null && salesLedger.getReviewStatus() == 1) { |
| | | // 审核操作:校验审核人不能是录入人(仅对未审核→已审核的转换) |
| | | if (existingLedger != null && existingLedger.getReviewStatus() != null && existingLedger.getReviewStatus() == 0) { |
| | | Long currentUserId = SecurityUtils.getUserId(); |
| | | String entryPerson = existingLedger.getEntryPerson(); |
| | | if (entryPerson != null && entryPerson.equals(String.valueOf(currentUserId))) { |
| | | throw new ServiceException("不能审核本人录入的订单"); |
| | | } |
| | | } |
| | | salesLedger.setReviewStatus(salesLedgerDto.getReviewStatus()); |
| | | } else if (salesLedger.getReviewStatus() != null && salesLedger.getReviewStatus() == 2) { |
| | | handleCounterReview(salesLedger); |
| | | } else { |
| | | // 未审核状态的编辑操作:校验已审核的订单不能编辑 |
| | | if (existingLedger != null && existingLedger.getReviewStatus() != null && existingLedger.getReviewStatus() == 1) { |
| | | throw new ServiceException("已审核的订单不能编辑"); |
| | | } |
| | | salesLedger.setReviewStatus(0); |
| | | } |
| | | salesLedgerMapper.updateById(salesLedger); |
| | | } |
| | |
| | | public SalesLedgerProcessRouteDto salesProcess(Long salesLedgerId) { |
| | | SalesLedgerProcessRouteDto dto = new SalesLedgerProcessRouteDto(); |
| | | List<SalesLedgerProcessRoute> list = baseMapper.selectSalesProcess(salesLedgerId); |
| | | List<SalesLedgerProcessRouteRecord> recordList = salesLedgerProcessRouteRecordService.list( |
| | | new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>() |
| | | .eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerId) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getId) |
| | | ); |
| | | if (CollectionUtils.isNotEmpty(list)) { |
| | | Long processRouteId = list.get(0).getProcessRouteId(); |
| | | ProcessRoute processRoute = processRouteMapper.selectById(processRouteId); |
| | |
| | | } |
| | | } |
| | | dto.setList(list); |
| | | if (CollectionUtils.isNotEmpty(list) && CollectionUtils.isNotEmpty(recordList)) { |
| | | Map<Long, Long> routeItemIdMap = list.stream() |
| | | .filter(item -> item.getId() != null && item.getProcessRouteItemId() != null) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, SalesLedgerProcessRoute::getProcessRouteItemId, (a, b) -> a)); |
| | | recordList.forEach(record -> { |
| | | if (record != null && record.getSalesLedgerProcessRouteId() != null) { |
| | | record.setProcessRouteItemId(routeItemIdMap.get(record.getSalesLedgerProcessRouteId())); |
| | | } |
| | | }); |
| | | } |
| | | dto.setRecordList(recordList); |
| | | return dto; |
| | | } |
| | | |
| | |
| | | if (selectedProduct.getProductModelId() == null) { |
| | | throw new ServiceException("入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | BigDecimal orderQty = selectedProduct.getQuantity() == null ? BigDecimal.ZERO : selectedProduct.getQuantity(); |
| | | BigDecimal qualifiedStocked = selectedProduct.getStockedQuantity() == null ? BigDecimal.ZERO : selectedProduct.getStockedQuantity(); |
| | | BigDecimal inboundQty = inboundQtyByLineId.getOrDefault(selectedProduct.getId(), BigDecimal.ZERO); |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) > 0 && qualifiedStocked.add(inboundQty).compareTo(orderQty) > 0) { |
| | | throw new ServiceException("入库失败,合格入库数量之和不能大于订单数量"); |
| | | } |
| | | } |
| | | String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_QUALIFIED); |
| | | if (StringUtils.isEmpty(approveUserIds)) { |
| | |
| | | } |
| | | BigDecimal oldStocked = dbProduct.getStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getStockedQuantity(); |
| | | BigDecimal newStocked = oldStocked.add(inboundThisLine); |
| | | BigDecimal orderQty = dbProduct.getQuantity() == null ? BigDecimal.ZERO : dbProduct.getQuantity(); |
| | | if (newStocked.compareTo(orderQty) > 0) { |
| | | throw new ServiceException("入库失败,合格入库数量之和不能大于订单数量"); |
| | | } |
| | | |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setRecordId(dbProduct.getId()); |
| | |
| | | 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; |
| | |
| | | if (selectedProduct.getProductModelId() == null) { |
| | | throw new ServiceException("不合格入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | BigDecimal orderQty = selectedProduct.getQuantity() == null ? BigDecimal.ZERO : selectedProduct.getQuantity(); |
| | | BigDecimal qualifiedStocked = selectedProduct.getStockedQuantity() == null ? BigDecimal.ZERO : selectedProduct.getStockedQuantity(); |
| | | BigDecimal unqualifiedStocked = selectedProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : selectedProduct.getUnqualifiedStockedQuantity(); |
| | | BigDecimal inboundQty = inboundQtyByLineId.getOrDefault(selectedProduct.getId(), BigDecimal.ZERO); |
| | | BigDecimal remainForUnqualified = orderQty.subtract(qualifiedStocked); |
| | | if (remainForUnqualified.compareTo(BigDecimal.ZERO) <= 0 && inboundQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw new ServiceException("不合格入库失败,该产品已无可入不合格库数量"); |
| | | } |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) > 0 && unqualifiedStocked.add(inboundQty).compareTo(orderQty) > 0) { |
| | | throw new ServiceException("不合格入库失败,不合格入库数量之和不能大于订单数量"); |
| | | } |
| | | if (inboundQty.compareTo(BigDecimal.ZERO) > 0 && unqualifiedStocked.add(inboundQty).compareTo(remainForUnqualified) > 0) { |
| | | throw new ServiceException("不合格入库失败,不合格入库数量不能大于订单数量减去合格入库数量"); |
| | | } |
| | | } |
| | | String approveUserIds = resolveApproveUserIds(dto.getApproveUserIds(), salesLedger.getId(), INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED); |
| | | if (StringUtils.isEmpty(approveUserIds)) { |
| | |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("不合格入库失败,产品规格未维护,无法入库"); |
| | | } |
| | | stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine, StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId()); |
| | | BigDecimal orderQty = dbProduct.getQuantity() == null ? BigDecimal.ZERO : dbProduct.getQuantity(); |
| | | BigDecimal qualifiedStocked = dbProduct.getStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getStockedQuantity(); |
| | | BigDecimal oldUnStocked = dbProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedStockedQuantity(); |
| | | dbProduct.setUnqualifiedStockedQuantity(oldUnStocked.add(inboundThisLine)); |
| | | BigDecimal newUnStocked = oldUnStocked.add(inboundThisLine); |
| | | BigDecimal remainForUnqualified = orderQty.subtract(qualifiedStocked); |
| | | if (remainForUnqualified.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("不合格入库失败,该产品已无可入不合格库数量"); |
| | | } |
| | | if (newUnStocked.compareTo(orderQty) > 0) { |
| | | throw new ServiceException("不合格入库失败,不合格入库数量之和不能大于订单数量"); |
| | | } |
| | | if (newUnStocked.compareTo(remainForUnqualified) > 0) { |
| | | throw new ServiceException("不合格入库失败,不合格入库数量不能大于订单数量减去合格入库数量"); |
| | | } |
| | | stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine, StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId()); |
| | | dbProduct.setUnqualifiedStockedQuantity(newUnStocked); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | |
| | | if (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 5) { |
| | | throw new ServiceException("出库失败,该销售订单已发货"); |
| | | } |
| | | if (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 2) { |
| | | throw new ServiceException("出库失败,该销售订单已发起发货审批,请先完成审批"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("销售订单出库失败,出库产品不能为空"); |
| | | } |
| | | String scanShippingNo = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SCAN"); |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | Map<Long, BigDecimal> outboundQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct line : dto.getSalesLedgerProductList()) { |
| | |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("出库失败,产品规格未维护,无法出库"); |
| | | } |
| | | BigDecimal orderQty = defaultDecimal(dbProduct.getQuantity()); |
| | | BigDecimal prevShipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | if (prevShipped.add(outboundThisLine).compareTo(orderQty) > 0) { |
| | | throw new ServiceException("出库失败,本次出库后累计发货数量不能大于该产品订单数量"); |
| | | } |
| | | stockUtils.assertQualifiedAvailable(dbProduct.getProductModelId(), outboundThisLine); |
| | | |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | |
| | | }); |
| | | boolean allLinesFull = ledgerAllProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2)); |
| | | salesLedger.setStockStatus(allLinesFull ? 2 : (anyInbound ? 1 : 0)); |
| | | List<SalesLedgerProduct> saleLines = ledgerAllProducts.stream() |
| | | .filter(p -> Objects.equals(p.getType(), saleType)) |
| | | .collect(Collectors.toList()); |
| | | boolean allDelivered = !saleLines.isEmpty() && saleLines.stream().allMatch(p -> { |
| | | BigDecimal q = defaultDecimal(p.getQuantity()); |
| | | BigDecimal s = defaultDecimal(p.getShippedQuantity()); |
| | | return q.compareTo(BigDecimal.ZERO) <= 0 || s.compareTo(q) >= 0; |
| | | }); |
| | | if (allDelivered) { |
| | | salesLedger.setDeliveryStatus(5); |
| | | } else { |
| | | boolean anyLineShipped = saleLines.stream() |
| | | .anyMatch(p -> defaultDecimal(p.getShippedQuantity()).compareTo(BigDecimal.ZERO) > 0); |
| | | if (anyLineShipped) { |
| | | salesLedger.setDeliveryStatus(6); |
| | | } |
| | | } |
| | | baseMapper.updateById(salesLedger); |
| | | syncShippingLedgerAfterQualifiedScan(ledgerId, scanShippingNo); |
| | | } |
| | | |
| | | /** |
| | | * 扫码合格出库后同步发货台账记录 |
| | | */ |
| | | private void syncShippingLedgerAfterQualifiedScan(Long ledgerId, String shippingBatchNo) { |
| | | if (shippingBatchNo == null) { |
| | | shippingBatchNo = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SCAN"); |
| | | } |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, ledgerId) |
| | | .eq(SalesLedgerProduct::getType, saleType)); |
| | | Date now = new Date(); |
| | | for (SalesLedgerProduct p : products) { |
| | | if (p.getShippedQuantity() == null || p.getShippedQuantity().compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | ShippingInfo row = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, p.getId()) |
| | | .orderByDesc(ShippingInfo::getId) |
| | | .last("LIMIT 1")); |
| | | BigDecimal lineQty = defaultDecimal(p.getQuantity()); |
| | | BigDecimal shipped = defaultDecimal(p.getShippedQuantity()); |
| | | boolean lineFullyShipped = lineQty.compareTo(BigDecimal.ZERO) <= 0 || shipped.compareTo(lineQty) >= 0; |
| | | String lineShipStatus = lineFullyShipped ? "已发货" : "部分发货"; |
| | | |
| | | if (row == null) { |
| | | ShippingInfo insert = new ShippingInfo(); |
| | | insert.setSalesLedgerId(ledgerId); |
| | | insert.setSalesLedgerProductId(p.getId()); |
| | | insert.setShippingNo(shippingBatchNo); |
| | | insert.setType("扫码出库"); |
| | | insert.setStatus(lineShipStatus); |
| | | insert.setShippingDate(now); |
| | | shippingInfoMapper.insert(insert); |
| | | } else { |
| | | if (!StringUtils.hasText(row.getType())) { |
| | | row.setType("扫码出库"); |
| | | } |
| | | row.setStatus(lineShipStatus); |
| | | row.setShippingDate(now); |
| | | if (!StringUtils.hasText(row.getShippingNo())) { |
| | | row.setShippingNo(shippingBatchNo); |
| | | } |
| | | shippingInfoMapper.updateById(row); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (dbProduct.getProductModelId() == null) { |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]产品规格未维护,无法补录出库"); |
| | | } |
| | | // 历史已发货补录:直接写入入库+出库记录 |
| | | stockUtils.addStock( |
| | | ledger.getId(), |
| | | dbProduct.getId(), |
| | | dbProduct.getProductModelId(), |
| | | allocQty, |
| | | StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode(), |
| | | dbProduct.getId() |
| | | ); |
| | | stockUtils.substractStock( |
| | | ledger.getId(), |
| | | dbProduct.getId(), |
| | | dbProduct.getProductModelId(), |
| | | allocQty, |
| | | StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), |
| | | dbProduct.getId() |
| | | ); |
| | | BigDecimal oldShipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | BigDecimal newShipped = oldShipped.add(allocQty); |
| | | dbProduct.setStockedQuantity(defaultDecimal(dbProduct.getQuantity())); |
| | | dbProduct.setShippedQuantity(newShipped); |
| | | dbProduct.setApproveStatus(3); |
| | | updateProductStockStatus(dbProduct); |
| | | dbProduct.fillRemainingQuantity(); |
| | | updateProductShipStatus(dbProduct); |
| | |
| | | throw new ServiceException("导入失败,订单编号[" + orderNo + "]存在重复发货记录,请勿重复导入"); |
| | | } |
| | | shippingInfoMapper.insert(shippingInfo); |
| | | createShippingQualityInspect(ledger, dbProduct, row, allocQty); |
| | | } |
| | | } |
| | | |
| | |
| | | BigDecimal shipped = defaultDecimal(p.getShippedQuantity()); |
| | | return shipped.compareTo(qty) >= 0; |
| | | }); |
| | | boolean anyInbound = CollectionUtils.isNotEmpty(latestProducts) && latestProducts.stream().anyMatch(p -> defaultDecimal(p.getStockedQuantity()).compareTo(BigDecimal.ZERO) > 0); |
| | | boolean allInbound = CollectionUtils.isNotEmpty(latestProducts) && latestProducts.stream().allMatch(p -> { |
| | | BigDecimal qty = defaultDecimal(p.getQuantity()); |
| | | BigDecimal stocked = defaultDecimal(p.getStockedQuantity()); |
| | | return qty.compareTo(BigDecimal.ZERO) <= 0 || stocked.compareTo(qty) >= 0; |
| | | }); |
| | | if (allShipped && rowList.get(0).getReportDate() != null) { |
| | | ledger.setDeliveryDate(DateUtils.toLocalDate(rowList.get(0).getReportDate())); |
| | | } |
| | | ledger.setStockStatus(allInbound ? 2 : (anyInbound ? 1 : 0)); |
| | | ledger.setDeliveryStatus(allShipped ? 5 : 1); |
| | | salesLedgerMapper.updateById(ledger); |
| | | } |
| | |
| | | String subCategory = StringUtils.hasText(row.getProductSubCategory()) ? row.getProductSubCategory().trim() : ""; |
| | | return ledgerId + "|" + subCategory + "|" + shippingNo + "|" + dateStr + "|" + defaultDecimal(row.getQuantity()); |
| | | } |
| | | |
| | | private void createShippingQualityInspect(SalesLedger ledger, SalesLedgerProduct dbProduct, SalesShippingImportDto row, BigDecimal inspectQty) { |
| | | if (ledger == null || dbProduct == null || inspectQty == null || inspectQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return; |
| | | } |
| | | Date checkDate = row.getReportDate() != null ? row.getReportDate() : new Date(); |
| | | QualityInspect qualityInspect = new QualityInspect(); |
| | | qualityInspect.setInspectType(2); |
| | | qualityInspect.setCheckTime(checkDate); |
| | | qualityInspect.setCustomer(StringUtils.hasText(ledger.getCustomerName()) ? ledger.getCustomerName() : row.getCustomerName()); |
| | | qualityInspect.setCheckName(StringUtils.hasText(row.getCreator()) ? row.getCreator().trim() : null); |
| | | qualityInspect.setProductId(dbProduct.getProductId()); |
| | | qualityInspect.setProductName(dbProduct.getProductCategory()); |
| | | qualityInspect.setModel(dbProduct.getSpecificationModel()); |
| | | qualityInspect.setUnit(resolveInspectUnit(dbProduct)); |
| | | qualityInspect.setQuantity(inspectQty); |
| | | qualityInspect.setQualifiedQuantity(inspectQty); |
| | | qualityInspect.setUnqualifiedQuantity(BigDecimal.ZERO); |
| | | qualityInspect.setPassRate(BigDecimal.valueOf(100)); |
| | | qualityInspect.setCheckResult("合格"); |
| | | qualityInspect.setInspectState(1); |
| | | qualityInspect.setApprovalStatus(1); |
| | | qualityInspect.setProductModelId(dbProduct.getProductModelId()); |
| | | |
| | | QualityTestStandard selectedStandard = null; |
| | | if (dbProduct.getProductId() != null) { |
| | | List<QualityTestStandard> standards = qualityTestStandardMapper.getQualityTestStandardByProductId(dbProduct.getProductId(), 2, null); |
| | | if (CollectionUtils.isNotEmpty(standards)) { |
| | | selectedStandard = standards.get(0); |
| | | qualityInspect.setTestStandardId(selectedStandard.getId()); |
| | | } |
| | | } |
| | | qualityInspectMapper.insert(qualityInspect); |
| | | |
| | | if (selectedStandard == null || selectedStandard.getId() == null) { |
| | | return; |
| | | } |
| | | List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, selectedStandard.getId())); |
| | | if (CollectionUtils.isEmpty(standardParams)) { |
| | | return; |
| | | } |
| | | List<QualityInspectParam> inspectParams = standardParams.stream().map(item -> { |
| | | QualityInspectParam param = new QualityInspectParam(); |
| | | param.setInspectId(qualityInspect.getId()); |
| | | param.setParameterItem(item.getParameterItem()); |
| | | param.setUnit(item.getUnit()); |
| | | param.setStandardValue(item.getStandardValue()); |
| | | param.setControlValue(item.getControlValue()); |
| | | param.setTestValue("无瑕疵"); |
| | | return param; |
| | | }).collect(Collectors.toList()); |
| | | inspectParams.forEach(qualityInspectParamMapper::insert); |
| | | } |
| | | |
| | | private String resolveInspectUnit(SalesLedgerProduct dbProduct) { |
| | | if (dbProduct == null) { |
| | | return null; |
| | | } |
| | | if (StringUtils.hasText(dbProduct.getUnit())) { |
| | | return dbProduct.getUnit(); |
| | | } |
| | | if (dbProduct.getProductModelId() == null) { |
| | | return null; |
| | | } |
| | | ProductModel productModel = productModelMapper.selectById(dbProduct.getProductModelId()); |
| | | if (productModel == null || !StringUtils.hasText(productModel.getUnit())) { |
| | | return null; |
| | | } |
| | | return productModel.getUnit(); |
| | | } |
| | | |
| | | private static final String SCAN_SHIP_REMARK_PREFIX = "SCAN_SHIP_DELIVERY_JSON:"; |
| | | |
| | | private static final class ScanShipPayload { |
| | | private String shippingNo; |
| | | private Long ledgerId; |
| | | private String car; |
| | | private String express; |
| | | private String shipType; |
| | | private Map<Long, BigDecimal> linesQty = new LinkedHashMap<>(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void scanShipApply(SalesScanShipDto dto) { |
| | | if (dto == null || dto.getSalesLedgerId() == null) { |
| | | throw new ServiceException("扫码发货失败,订单不能为空"); |
| | | } |
| | | if (StringUtils.isEmpty(dto.getApproveUserIds())) { |
| | | throw new ServiceException("请选择审批人"); |
| | | } |
| | | if (CollectionUtils.isEmpty(dto.getSalesLedgerProductList())) { |
| | | throw new ServiceException("请填写发货产品行"); |
| | | } |
| | | String shipType = StringUtils.hasText(dto.getShipType()) ? dto.getShipType().trim() : "货车"; |
| | | if ("货车".equals(shipType)) { |
| | | if (!StringUtils.hasText(dto.getShippingCarNumber())) { |
| | | throw new ServiceException("请填写车牌号"); |
| | | } |
| | | } else if ("快递".equals(shipType)) { |
| | | if (!StringUtils.hasText(dto.getExpressNumber())) { |
| | | 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 (salesLedger.getDeliveryStatus() != null && salesLedger.getDeliveryStatus() == 2) { |
| | | throw new ServiceException("该销售订单已发起发货审批,请先完成审批"); |
| | | } |
| | | List<SalesLedgerProduct> notStocked = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()) |
| | | .eq(SalesLedgerProduct::getType, 1) |
| | | .ne(SalesLedgerProduct::getProductStockStatus, 2)); |
| | | if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(notStocked)) { |
| | | throw new ServiceException("发货失败,该销售订单存在未入库产品,请先完成全部入库后再发货"); |
| | | } |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | Map<Long, BigDecimal> shipQtyByLineId = new LinkedHashMap<>(); |
| | | for (SalesLedgerProduct line : dto.getSalesLedgerProductList()) { |
| | | if (line == null || line.getId() == null) { |
| | | throw new ServiceException("产品信息不完整"); |
| | | } |
| | | BigDecimal q = line.getStockedQuantity(); |
| | | if (q == null) { |
| | | throw new ServiceException("发货数量不能为空"); |
| | | } |
| | | if (q.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("发货数量不能为负数"); |
| | | } |
| | | shipQtyByLineId.merge(line.getId(), q, BigDecimal::add); |
| | | } |
| | | boolean anyPositive = shipQtyByLineId.values().stream().anyMatch(v -> v.compareTo(BigDecimal.ZERO) > 0); |
| | | if (!anyPositive) { |
| | | throw new ServiceException("请至少填写一行大于 0 的发货数量"); |
| | | } |
| | | Long ledgerId = salesLedger.getId(); |
| | | for (Map.Entry<Long, BigDecimal> entry : shipQtyByLineId.entrySet()) { |
| | | if (entry.getValue().compareTo(BigDecimal.ZERO) == 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(entry.getKey()); |
| | | 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 orderQty = defaultDecimal(dbProduct.getQuantity()); |
| | | BigDecimal prevShipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | if (prevShipped.add(entry.getValue()).compareTo(orderQty) > 0) { |
| | | throw new ServiceException("累计发货数量不能大于该产品订单数量"); |
| | | } |
| | | stockUtils.assertQualifiedAvailable(dbProduct.getProductModelId(), entry.getValue()); |
| | | } |
| | | String shNo = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SH"); |
| | | Map<Long, BigDecimal> positiveLines = new LinkedHashMap<>(); |
| | | for (Map.Entry<Long, BigDecimal> e : shipQtyByLineId.entrySet()) { |
| | | if (e.getValue().compareTo(BigDecimal.ZERO) > 0) { |
| | | positiveLines.put(e.getKey(), e.getValue()); |
| | | } |
| | | } |
| | | for (Map.Entry<Long, BigDecimal> e : positiveLines.entrySet()) { |
| | | ShippingInfo si = new ShippingInfo(); |
| | | si.setSalesLedgerId(ledgerId); |
| | | si.setSalesLedgerProductId(e.getKey()); |
| | | si.setShippingNo(shNo); |
| | | si.setStatus("待审核"); |
| | | si.setType(shipType); |
| | | if ("货车".equals(shipType)) { |
| | | si.setShippingCarNumber(dto.getShippingCarNumber().trim()); |
| | | } |
| | | if ("快递".equals(shipType)) { |
| | | si.setExpressNumber(dto.getExpressNumber().trim()); |
| | | } |
| | | shippingInfoMapper.insert(si); |
| | | } |
| | | String remarkJson = buildScanShipRemarkJson(shNo, ledgerId, dto, positiveLines); |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | ApproveProcessVO approveProcessVO = new ApproveProcessVO(); |
| | | approveProcessVO.setApproveType(7); |
| | | approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId()); |
| | | approveProcessVO.setApproveReason("发货审批:" + salesLedger.getSalesContractNo()); |
| | | approveProcessVO.setApproveRemark(remarkJson); |
| | | approveProcessVO.setApproveUserIds(dto.getApproveUserIds().trim()); |
| | | approveProcessVO.setApproveUser(loginUser.getUserId()); |
| | | approveProcessVO.setApproveTime(LocalDate.now().toString()); |
| | | approveProcessVO.setTempFileIds(dto.getTempFileIds()); |
| | | try { |
| | | approveProcessService.addApprove(approveProcessVO); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("发起发货审批失败: " + e.getMessage()); |
| | | } |
| | | salesLedger.setDeliveryStatus(2); |
| | | baseMapper.updateById(salesLedger); |
| | | } |
| | | |
| | | private String buildScanShipRemarkJson(String shippingNo, Long ledgerId, SalesScanShipDto dto, Map<Long, BigDecimal> lines) { |
| | | try { |
| | | ObjectMapper om = new ObjectMapper(); |
| | | ObjectNode root = om.createObjectNode(); |
| | | root.put("shippingNo", shippingNo); |
| | | root.put("ledgerId", ledgerId); |
| | | root.put("car", dto.getShippingCarNumber() == null ? "" : dto.getShippingCarNumber().trim()); |
| | | root.put("express", dto.getExpressNumber() == null ? "" : dto.getExpressNumber().trim()); |
| | | root.put("shipType", dto.getShipType() == null ? "货车" : dto.getShipType().trim()); |
| | | ObjectNode linesNode = om.createObjectNode(); |
| | | for (Map.Entry<Long, BigDecimal> e : lines.entrySet()) { |
| | | linesNode.put(String.valueOf(e.getKey()), e.getValue().stripTrailingZeros().toPlainString()); |
| | | } |
| | | root.set("lines", linesNode); |
| | | return SCAN_SHIP_REMARK_PREFIX + om.writeValueAsString(root); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("构建发货审批参数失败"); |
| | | } |
| | | } |
| | | |
| | | private ScanShipPayload parseScanShipPayload(String remark) { |
| | | if (!StringUtils.hasText(remark) || !remark.startsWith(SCAN_SHIP_REMARK_PREFIX)) { |
| | | return null; |
| | | } |
| | | try { |
| | | String json = remark.substring(SCAN_SHIP_REMARK_PREFIX.length()); |
| | | ObjectMapper om = new ObjectMapper(); |
| | | JsonNode n = om.readTree(json); |
| | | ScanShipPayload p = new ScanShipPayload(); |
| | | p.shippingNo = n.path("shippingNo").asText(null); |
| | | p.ledgerId = n.path("ledgerId").asLong(0L); |
| | | p.car = n.path("car").asText(""); |
| | | p.express = n.path("express").asText(""); |
| | | p.shipType = n.path("shipType").asText("货车"); |
| | | JsonNode lines = n.path("lines"); |
| | | p.linesQty = new LinkedHashMap<>(); |
| | | if (lines.isObject()) { |
| | | Iterator<String> it = lines.fieldNames(); |
| | | while (it.hasNext()) { |
| | | String k = it.next(); |
| | | p.linesQty.put(Long.valueOf(k), new BigDecimal(lines.get(k).asText())); |
| | | } |
| | | } |
| | | return p; |
| | | } catch (Exception e) { |
| | | log.warn("解析扫码发货审批备注失败: {}", e.getMessage()); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void onScanShipDeliveryApproveOutcome(ApproveProcess approveProcess, Integer outcomeStatus) { |
| | | if (approveProcess == null) { |
| | | return; |
| | | } |
| | | ScanShipPayload ctx = parseScanShipPayload(approveProcess.getApproveRemark()); |
| | | if (ctx == null || ctx.ledgerId == null || ctx.ledgerId <= 0 || !StringUtils.hasText(ctx.shippingNo)) { |
| | | return; |
| | | } |
| | | if (outcomeStatus != null && outcomeStatus == 2) { |
| | | executeScanShipDeliveryApproved(approveProcess, ctx); |
| | | } else if (outcomeStatus != null && outcomeStatus == 3) { |
| | | updateScanShipBatchShippingStatus(ctx.ledgerId, ctx.shippingNo, "审核拒绝"); |
| | | SalesLedger sl = baseMapper.selectById(ctx.ledgerId); |
| | | if (sl != null) { |
| | | sl.setDeliveryStatus(3); |
| | | baseMapper.updateById(sl); |
| | | } |
| | | } else if (outcomeStatus != null && outcomeStatus == 1) { |
| | | updateScanShipBatchShippingStatus(ctx.ledgerId, ctx.shippingNo, "审核中"); |
| | | } |
| | | } |
| | | |
| | | private void updateScanShipBatchShippingStatus(Long ledgerId, String shippingNo, String statusText) { |
| | | if (ledgerId == null || !StringUtils.hasText(shippingNo)) { |
| | | return; |
| | | } |
| | | shippingInfoMapper.update(null, new UpdateWrapper<ShippingInfo>().lambda() |
| | | .set(ShippingInfo::getStatus, statusText) |
| | | .eq(ShippingInfo::getSalesLedgerId, ledgerId) |
| | | .eq(ShippingInfo::getShippingNo, shippingNo)); |
| | | } |
| | | |
| | | private void executeScanShipDeliveryApproved(ApproveProcess approveProcess, ScanShipPayload ctx) { |
| | | int saleType = SaleEnum.SALE.getCode(); |
| | | Date now = new Date(); |
| | | List<ShippingInfo> batch = shippingInfoMapper.selectList(Wrappers.<ShippingInfo>lambdaQuery() |
| | | .eq(ShippingInfo::getSalesLedgerId, ctx.ledgerId) |
| | | .eq(ShippingInfo::getShippingNo, ctx.shippingNo)); |
| | | if (CollectionUtils.isEmpty(batch)) { |
| | | log.warn("扫码发货审批通过但未找到发货台账 batch ledgerId={} shippingNo={}", ctx.ledgerId, ctx.shippingNo); |
| | | return; |
| | | } |
| | | for (Map.Entry<Long, BigDecimal> entry : ctx.linesQty.entrySet()) { |
| | | Long productLineId = entry.getKey(); |
| | | BigDecimal shipQty = entry.getValue(); |
| | | if (shipQty == null || shipQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectById(productLineId); |
| | | if (dbProduct == null) { |
| | | throw new ServiceException("销售产品不存在"); |
| | | } |
| | | ShippingInfo row = batch.stream() |
| | | .filter(si -> Objects.equals(si.getSalesLedgerProductId(), productLineId)) |
| | | .findFirst() |
| | | .orElse(null); |
| | | if (row == null) { |
| | | throw new ServiceException("未找到对应发货台账行"); |
| | | } |
| | | if (!"已发货".equals(row.getStatus())) { |
| | | stockUtils.substractStock(ctx.ledgerId, productLineId, dbProduct.getProductModelId(), shipQty, |
| | | StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), row.getId()); |
| | | BigDecimal oldShipped = defaultDecimal(dbProduct.getShippedQuantity()); |
| | | dbProduct.setShippedQuantity(oldShipped.add(shipQty)); |
| | | dbProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.updateById(dbProduct); |
| | | } |
| | | row.setStatus("已发货"); |
| | | row.setShippingDate(now); |
| | | if (StringUtils.hasText(ctx.car)) { |
| | | row.setShippingCarNumber(ctx.car.trim()); |
| | | } |
| | | if (StringUtils.hasText(ctx.express)) { |
| | | row.setExpressNumber(ctx.express.trim()); |
| | | } |
| | | if (StringUtils.hasText(ctx.shipType)) { |
| | | row.setType(ctx.shipType.trim()); |
| | | } |
| | | shippingInfoMapper.updateById(row); |
| | | } |
| | | List<Long> shippingIds = batch.stream().map(ShippingInfo::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | commonFileService.copyApproveProcessShipAttachmentsToShippingInfos(approveProcess.getId(), shippingIds); |
| | | List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ctx.ledgerId)); |
| | | SalesLedger salesLedger = baseMapper.selectById(ctx.ledgerId); |
| | | if (salesLedger == null) { |
| | | return; |
| | | } |
| | | 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)); |
| | | List<SalesLedgerProduct> saleLines = ledgerAllProducts.stream() |
| | | .filter(p -> Objects.equals(p.getType(), saleType)) |
| | | .collect(Collectors.toList()); |
| | | boolean allDelivered = !saleLines.isEmpty() && saleLines.stream().allMatch(p -> { |
| | | BigDecimal q = defaultDecimal(p.getQuantity()); |
| | | BigDecimal s = defaultDecimal(p.getShippedQuantity()); |
| | | return q.compareTo(BigDecimal.ZERO) <= 0 || s.compareTo(q) >= 0; |
| | | }); |
| | | if (allDelivered) { |
| | | salesLedger.setDeliveryStatus(5); |
| | | } else { |
| | | boolean anyLineShipped = saleLines.stream() |
| | | .anyMatch(p -> defaultDecimal(p.getShippedQuantity()).compareTo(BigDecimal.ZERO) > 0); |
| | | if (anyLineShipped) { |
| | | salesLedger.setDeliveryStatus(6); |
| | | } |
| | | } |
| | | baseMapper.updateById(salesLedger); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 处理销售台账反审逻辑 |
| | | * 1. 设置反审相关信息(时间、人员) |
| | | * 2. 复制原销售台账及产品数据,生成新的台账 |
| | | * 3. 对原台账的库存数据进行反向操作 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public List<Long> counterReview(CounterReviewDto dto) { |
| | | if (dto == null || CollectionUtils.isEmpty(dto.getIds())) { |
| | | throw new ServiceException("请选择要反审核的订单"); |
| | | } |
| | | if (dto.getCounterReviewType() == null || (dto.getCounterReviewType() != 1 && dto.getCounterReviewType() != 2)) { |
| | | throw new ServiceException("请选择反审核类型:作废或重新生成"); |
| | | } |
| | | if (dto.getCounterReviewDesc() == null || dto.getCounterReviewDesc().trim().isEmpty()) { |
| | | throw new ServiceException("请输入反审核描述"); |
| | | } |
| | | |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | List<Long> newLedgerIds = new ArrayList<>(); |
| | | |
| | | for (Long id : dto.getIds()) { |
| | | SalesLedger originalLedger = salesLedgerMapper.selectById(id); |
| | | if (originalLedger == null) { |
| | | throw new ServiceException("订单不存在,无法反审核"); |
| | | } |
| | | if (originalLedger.getReviewStatus() == null || originalLedger.getReviewStatus() != 1) { |
| | | throw new ServiceException("订单" + originalLedger.getSalesContractNo() + "不是已审核状态,无法反审核"); |
| | | } |
| | | |
| | | // 1. 标记原订单为已反审 |
| | | originalLedger.setReviewStatus(2); |
| | | originalLedger.setCounterReviewTime(LocalDateTime.now()); |
| | | originalLedger.setCounterReviewPerson(loginUser.getUser().getNickName()); |
| | | originalLedger.setCounterReviewPersonId(loginUser.getUserId()); |
| | | originalLedger.setCounterReviewType(dto.getCounterReviewType()); |
| | | originalLedger.setCounterReviewDesc(dto.getCounterReviewDesc()); |
| | | salesLedgerMapper.updateById(originalLedger); |
| | | |
| | | // 2. 作废库存:入库扣减、出库增加、删除记录 |
| | | processOriginalOrderStock(id); |
| | | |
| | | // 3. 清除质检记录 |
| | | clearQualityInspectRecords(id); |
| | | |
| | | // 4. 清除发货信息和发货审批记录 |
| | | clearShippingAndApprovalRecords(id); |
| | | |
| | | // 5. 取消审批流程 |
| | | cancelApproveProcesses(id, originalLedger.getSalesContractNo()); |
| | | |
| | | // 6. 重新生成:创建新台账副本 |
| | | if (dto.getCounterReviewType() == 2) { |
| | | SalesLedger newLedger = new SalesLedger(); |
| | | BeanUtils.copyProperties(originalLedger, newLedger); |
| | | newLedger.setId(null); |
| | | newLedger.setSalesContractNo(generateSalesContractNo()); |
| | | newLedger.setDeliveryStatus(1); |
| | | newLedger.setStockStatus(0); |
| | | newLedger.setReviewStatus(0); |
| | | newLedger.setCounterReviewTime(null); |
| | | newLedger.setCounterReviewPerson(null); |
| | | newLedger.setCounterReviewPersonId(null); |
| | | newLedger.setCounterReviewType(null); |
| | | newLedger.setCounterReviewDesc(null); |
| | | salesLedgerMapper.insert(newLedger); |
| | | |
| | | // 复制产品到新台账 |
| | | List<SalesLedgerProduct> originalProducts = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, id) |
| | | ); |
| | | for (SalesLedgerProduct originalProduct : originalProducts) { |
| | | SalesLedgerProduct newProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(originalProduct, newProduct); |
| | | newProduct.setId(null); |
| | | newProduct.setSalesLedgerId(newLedger.getId()); |
| | | newProduct.setStockedQuantity(BigDecimal.ZERO); |
| | | newProduct.setShippedQuantity(BigDecimal.ZERO); |
| | | newProduct.setUnqualifiedStockedQuantity(BigDecimal.ZERO); |
| | | newProduct.setUnqualifiedShippedQuantity(BigDecimal.ZERO); |
| | | newProduct.setReturnQuality(BigDecimal.ZERO); |
| | | newProduct.setAvailableQuality(newProduct.getQuantity().subtract(newProduct.getReturnQuality())); |
| | | newProduct.setProductStockStatus(0); |
| | | newProduct.fillRemainingQuantity(); |
| | | salesLedgerProductMapper.insert(newProduct); |
| | | } |
| | | newLedgerIds.add(newLedger.getId()); |
| | | } |
| | | } |
| | | return newLedgerIds; |
| | | } |
| | | |
| | | /** |
| | | * 旧版反审处理(兼容 addOrUpdateSalesLedger 中 reviewStatus=2 的调用) |
| | | */ |
| | | private void handleCounterReview(SalesLedger salesLedger) { |
| | | // 1. 设置反审相关信息 |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | salesLedger.setCounterReviewTime(LocalDateTime.now()); |
| | | salesLedger.setCounterReviewPerson(loginUser.getUser().getNickName()); |
| | | salesLedger.setCounterReviewPersonId(loginUser.getUserId()); |
| | | salesLedger.setReviewStatus(2); |
| | | |
| | | Long originalSalesLedgerId = salesLedger.getId(); |
| | | |
| | | // 2. 查询原销售台账数据 |
| | | SalesLedger originalLedger = salesLedgerMapper.selectById(originalSalesLedgerId); |
| | | if (originalLedger == null) { |
| | | throw new ServiceException("原订单不存在,无法反审"); |
| | | } |
| | | |
| | | // 3. 创建新的销售台账,复制原台账数据 |
| | | SalesLedger newLedger = new SalesLedger(); |
| | | BeanUtils.copyProperties(originalLedger, newLedger); |
| | | newLedger.setId(null); // 清空ID,准备插入新记录 |
| | | newLedger.setSalesContractNo(generateSalesContractNo()); // 生成新合同号 |
| | | newLedger.setDeliveryStatus(1); // 设置为未发货状态 |
| | | newLedger.setStockStatus(0); // 设置为未入库状态 |
| | | newLedger.setReviewStatus(0); // 设置为未审核状态 |
| | | newLedger.setCounterReviewTime(null); // 清空反审时间 |
| | | newLedger.setCounterReviewPerson(null); // 清空反审人 |
| | | newLedger.setCounterReviewPersonId(null); // 清空反审人ID |
| | | |
| | | // 4. 插入新的销售台账 |
| | | salesLedgerMapper.insert(newLedger); |
| | | |
| | | // 5. 查询并复制原台账的所有产品数据 |
| | | List<SalesLedgerProduct> originalProducts = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | for (SalesLedgerProduct originalProduct : originalProducts) { |
| | | // 5.1 创建新产品记录,复制原产品数据 |
| | | SalesLedgerProduct newProduct = new SalesLedgerProduct(); |
| | | BeanUtils.copyProperties(originalProduct, newProduct); |
| | | newProduct.setId(null); // 清空ID,准备插入新记录 |
| | | newProduct.setSalesLedgerId(newLedger.getId()); // 关联到新的台账ID |
| | | newProduct.setStockedQuantity(BigDecimal.ZERO); // 已入库数量重置为0 |
| | | newProduct.setShippedQuantity(BigDecimal.ZERO); // 已出库数量重置为0 |
| | | newProduct.setUnqualifiedStockedQuantity(BigDecimal.ZERO); // 不合格入库数量重置为0 |
| | | newProduct.setUnqualifiedShippedQuantity(BigDecimal.ZERO); // 不合格出库数量重置为0 |
| | | newProduct.setReturnQuality(BigDecimal.ZERO); // 退货数量重置为0 |
| | | newProduct.setAvailableQuality(newProduct.getQuantity().subtract(newProduct.getReturnQuality())); // 重新计算可用数量 |
| | | newProduct.setProductStockStatus(0); // 产品库存状态重置为0 |
| | | newProduct.fillRemainingQuantity(); // 重新计算剩余数量 |
| | | |
| | | // 5.2 插入新产品记录 |
| | | salesLedgerProductMapper.insert(newProduct); |
| | | } |
| | | |
| | | // 6. 处理原订单的库存数据(生成反审出入库记录) |
| | | processOriginalOrderStock(originalSalesLedgerId); |
| | | |
| | | // 7. 清除原订单的质检记录 |
| | | clearQualityInspectRecords(originalSalesLedgerId); |
| | | |
| | | // 8. 清除原订单的发货信息和发货审批记录 |
| | | clearShippingAndApprovalRecords(originalSalesLedgerId); |
| | | |
| | | // 9. 取消原订单相关的审批流程 |
| | | cancelApproveProcesses(originalSalesLedgerId, originalLedger.getSalesContractNo()); |
| | | } |
| | | |
| | | /** |
| | | * 清除原订单的质检记录 |
| | | */ |
| | | private void clearQualityInspectRecords(Long originalSalesLedgerId) { |
| | | // 删除与原订单关联的质检记录 |
| | | qualityInspectMapper.delete( |
| | | Wrappers.<QualityInspect>lambdaQuery() |
| | | .eq(QualityInspect::getPurchaseLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 清除原订单的发货信息和发货审批记录 |
| | | */ |
| | | private void clearShippingAndApprovalRecords(Long originalSalesLedgerId) { |
| | | // 1. 查询原订单的所有发货信息 |
| | | List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList( |
| | | Wrappers.<ShippingInfo>lambdaQuery() |
| | | .eq(ShippingInfo::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 2. 删除发货审批记录 |
| | | if (!CollectionUtils.isEmpty(shippingInfos)) { |
| | | List<Long> shippingInfoIds = shippingInfos.stream() |
| | | .map(ShippingInfo::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | shipmentApprovalMapper.delete( |
| | | Wrappers.<ShipmentApproval>lambdaQuery() |
| | | .eq(ShipmentApproval::getSalesLedgerId, originalSalesLedgerId) |
| | | .or() |
| | | .in(ShipmentApproval::getShippingInfoId, shippingInfoIds) |
| | | ); |
| | | |
| | | // 3. 删除发货信息记录 |
| | | shippingInfoMapper.delete( |
| | | Wrappers.<ShippingInfo>lambdaQuery() |
| | | .eq(ShippingInfo::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 取消原订单相关的审批流程 |
| | | */ |
| | | private void cancelApproveProcesses(Long originalSalesLedgerId, String originalSalesContractNo) { |
| | | // 取消入库审批流程 |
| | | List<ApproveProcess> stockInApproveProcesses = approveProcessService.list( |
| | | new LambdaQueryWrapper<ApproveProcess>() |
| | | .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()) |
| | | .like(ApproveProcess::getApproveRemark, "salesStock:" + originalSalesLedgerId + ":") |
| | | .eq(ApproveProcess::getApproveDelete, 0) |
| | | ); |
| | | |
| | | for (ApproveProcess process : stockInApproveProcesses) { |
| | | process.setApproveStatus(3); // 设置为审批失败状态 |
| | | process.setApproveDelete(1); // 标记为已删除 |
| | | approveProcessService.updateById(process); |
| | | } |
| | | |
| | | // 取消发货审批流程 |
| | | List<ApproveProcess> deliveryApproveProcesses = approveProcessService.list( |
| | | new LambdaQueryWrapper<ApproveProcess>() |
| | | .eq(ApproveProcess::getApproveType, 7) // 发货审批类型 |
| | | .like(ApproveProcess::getApproveReason, "发货审批:" + originalSalesContractNo) |
| | | .eq(ApproveProcess::getApproveDelete, 0) |
| | | ); |
| | | |
| | | for (ApproveProcess process : deliveryApproveProcesses) { |
| | | process.setApproveStatus(3); // 设置为审批失败状态 |
| | | process.setApproveDelete(1); // 标记为已删除 |
| | | approveProcessService.updateById(process); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理原订单的库存数据 |
| | | * 1. 删除原订单的所有入库记录,并扣减库存 |
| | | * 2. 删除原订单的所有出库记录,并增加库存 |
| | | */ |
| | | private void processOriginalOrderStock(Long originalSalesLedgerId) { |
| | | // 1. 查询原订单的所有入库记录 |
| | | List<StockInRecord> stockInRecords = stockInRecordMapper.selectList( |
| | | Wrappers.<StockInRecord>lambdaQuery() |
| | | .eq(StockInRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 2. 删除入库记录并扣减库存 |
| | | for (StockInRecord stockInRecord : stockInRecords) { |
| | | // 从库存表中扣减相应数量 |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setProductModelId(stockInRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockInRecord.getStockInNum()); |
| | | stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); |
| | | } |
| | | |
| | | // 3. 删除所有入库记录 |
| | | stockInRecordMapper.delete( |
| | | Wrappers.<StockInRecord>lambdaQuery() |
| | | .eq(StockInRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 4. 查询原订单的所有出库记录 |
| | | List<StockOutRecord> stockOutRecords = stockOutRecordMapper.selectList( |
| | | Wrappers.<StockOutRecord>lambdaQuery() |
| | | .eq(StockOutRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | |
| | | // 5. 删除出库记录并增加库存 |
| | | for (StockOutRecord stockOutRecord : stockOutRecords) { |
| | | // 向库存表中增加相应数量 |
| | | StockInventoryDto stockInventoryDto = new StockInventoryDto(); |
| | | stockInventoryDto.setProductModelId(stockOutRecord.getProductModelId()); |
| | | stockInventoryDto.setQualitity(stockOutRecord.getStockOutNum()); |
| | | stockInventoryMapper.updateAddStockInventory(stockInventoryDto); |
| | | } |
| | | |
| | | // 6. 删除所有出库记录 |
| | | stockOutRecordMapper.delete( |
| | | Wrappers.<StockOutRecord>lambdaQuery() |
| | | .eq(StockOutRecord::getSalesLedgerId, originalSalesLedgerId) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void markOrderCompleted(List<Long> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | throw new ServiceException("请选择要标记完成的订单"); |
| | | } |
| | | for (Long id : ids) { |
| | | SalesLedger ledger = salesLedgerMapper.selectById(id); |
| | | if (ledger == null) { |
| | | throw new ServiceException("订单不存在,无法标记完成"); |
| | | } |
| | | if (ledger.getReviewStatus() == null || ledger.getReviewStatus() != 1) { |
| | | throw new ServiceException("订单" + ledger.getSalesContractNo() + "不是已审核状态,无法标记完成"); |
| | | } |
| | | if (ledger.getOrderStatus() != null && ledger.getOrderStatus() == 1) { |
| | | throw new ServiceException("订单" + ledger.getSalesContractNo() + "已完成,无需重复标记"); |
| | | } |
| | | } |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .in(SalesLedger::getId, ids) |
| | | .set(SalesLedger::getOrderStatus, 1) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public void incrementPrintCount(Long id, String printType) { |
| | | if (id == null) { |
| | | throw new ServiceException("销售台账ID不能为空"); |
| | | } |
| | | if (printType == null || (!"label".equals(printType) && !"document".equals(printType))) { |
| | | throw new ServiceException("打印类型必须为 label 或 document"); |
| | | } |
| | | SalesLedger ledger = salesLedgerMapper.selectById(id); |
| | | if (ledger == null) { |
| | | throw new ServiceException("销售台账不存在"); |
| | | } |
| | | if ("label".equals(printType)) { |
| | | int currentCount = ledger.getLabelPrintCount() == null ? 0 : ledger.getLabelPrintCount(); |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .eq(SalesLedger::getId, id) |
| | | .set(SalesLedger::getLabelPrintCount, currentCount + 1) |
| | | ); |
| | | } else { |
| | | int currentCount = ledger.getDocumentPrintCount() == null ? 0 : ledger.getDocumentPrintCount(); |
| | | salesLedgerMapper.update(null, |
| | | Wrappers.<SalesLedger>lambdaUpdate() |
| | | .eq(SalesLedger::getId, id) |
| | | .set(SalesLedger::getDocumentPrintCount, currentCount + 1) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void exportWithProducts(HttpServletResponse response, SalesLedgerDto salesLedgerDto) { |
| | | try { |
| | | // 1. 查询销售台账列表(导出使用升序排序) |
| | | Page<SalesLedger> page = new Page<>(-1, -1); |
| | | // 使用 Wrappers 构建升序查询 |
| | | LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.<SalesLedger>lambdaQuery() |
| | | .orderByAsc(SalesLedger::getEntryDate) |
| | | .orderByAsc(SalesLedger::getId); |
| | | |
| | | // 添加查询条件 |
| | | if (salesLedgerDto.getCustomerName() != null && !salesLedgerDto.getCustomerName().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getCustomerName, salesLedgerDto.getCustomerName()); |
| | | } |
| | | if (salesLedgerDto.getSalesContractNo() != null && !salesLedgerDto.getSalesContractNo().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getSalesContractNo, salesLedgerDto.getSalesContractNo()); |
| | | } |
| | | if (salesLedgerDto.getProjectName() != null && !salesLedgerDto.getProjectName().isEmpty()) { |
| | | queryWrapper.like(SalesLedger::getProjectName, salesLedgerDto.getProjectName()); |
| | | } |
| | | if (salesLedgerDto.getEntryDateStart() != null && !salesLedgerDto.getEntryDateStart().isEmpty()) { |
| | | queryWrapper.ge(SalesLedger::getEntryDate, salesLedgerDto.getEntryDateStart()); |
| | | } |
| | | if (salesLedgerDto.getEntryDateEnd() != null && !salesLedgerDto.getEntryDateEnd().isEmpty()) { |
| | | queryWrapper.le(SalesLedger::getEntryDate, salesLedgerDto.getEntryDateEnd()); |
| | | } |
| | | if (salesLedgerDto.getDeliveryStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getDeliveryStatus, salesLedgerDto.getDeliveryStatus()); |
| | | } |
| | | if (salesLedgerDto.getStockStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getStockStatus, salesLedgerDto.getStockStatus()); |
| | | } |
| | | if (salesLedgerDto.getReviewStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getReviewStatus, salesLedgerDto.getReviewStatus()); |
| | | } |
| | | if (salesLedgerDto.getOrderStatus() != null) { |
| | | queryWrapper.eq(SalesLedger::getOrderStatus, salesLedgerDto.getOrderStatus()); |
| | | } |
| | | if (salesLedgerDto.getReviewStatusList() != null && !salesLedgerDto.getReviewStatusList().isEmpty()) { |
| | | queryWrapper.and(w -> w.in(SalesLedger::getReviewStatus, salesLedgerDto.getReviewStatusList()) |
| | | .or().isNull(SalesLedger::getReviewStatus)); |
| | | } |
| | | |
| | | IPage<SalesLedger> ledgerPage = salesLedgerMapper.selectPage(page, queryWrapper); |
| | | List<SalesLedger> ledgerList = ledgerPage.getRecords(); |
| | | |
| | | // 2. 收集数据 |
| | | List<SalesLedgerExportDto> ledgerExportList = new ArrayList<>(); |
| | | List<SalesLedgerProductExportDto> productExportList = new ArrayList<>(); |
| | | |
| | | for (SalesLedger ledger : ledgerList) { |
| | | // 转换台账数据 |
| | | SalesLedgerExportDto ledgerDto = new SalesLedgerExportDto(); |
| | | ledgerDto.setSalesContractNo(ledger.getSalesContractNo()); |
| | | ledgerDto.setCustomerContractNo(ledger.getCustomerContractNo()); |
| | | ledgerDto.setProjectName(ledger.getProjectName()); |
| | | ledgerDto.setCustomerName(ledger.getCustomerName()); |
| | | ledgerDto.setSalesman(ledger.getSalesman()); |
| | | ledgerDto.setEntryPersonName(ledger.getEntryPersonName()); |
| | | ledgerDto.setEntryDate(ledger.getEntryDate()); |
| | | ledgerDto.setExecutionDate(ledger.getExecutionDate() != null ? |
| | | java.sql.Date.valueOf(ledger.getExecutionDate()) : null); |
| | | ledgerDto.setDeliveryDate(ledger.getDeliveryDate() != null ? |
| | | java.sql.Date.valueOf(ledger.getDeliveryDate()) : null); |
| | | ledgerDto.setContractAmount(ledger.getContractAmount()); |
| | | ledgerDto.setRemarks(ledger.getRemarks()); |
| | | ledgerDto.setCustomerRemarks(ledger.getCustomerRemarks()); |
| | | ledgerDto.setDeliveryStatusText(getDeliveryStatusText(ledger.getDeliveryStatus())); |
| | | ledgerDto.setStockStatusText(getStockStatusText(ledger.getStockStatus())); |
| | | ledgerDto.setReviewStatusText(getReviewStatusText(ledger.getReviewStatus())); |
| | | ledgerDto.setOrderStatusText(getOrderStatusText(ledger.getOrderStatus())); |
| | | ledgerExportList.add(ledgerDto); |
| | | |
| | | // 查询该台账的产品列表 |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( |
| | | Wrappers.<SalesLedgerProduct>lambdaQuery() |
| | | .eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()) |
| | | .eq(SalesLedgerProduct::getType, 1) |
| | | ); |
| | | |
| | | for (SalesLedgerProduct product : products) { |
| | | SalesLedgerProductExportDto productDto = new SalesLedgerProductExportDto(); |
| | | productDto.setSalesContractNo(ledger.getSalesContractNo()); |
| | | productDto.setProductCategory(product.getProductCategory()); |
| | | productDto.setSpecificationModel(product.getSpecificationModel()); |
| | | productDto.setThickness(product.getThickness()); |
| | | productDto.setFloorCode(product.getFloorCode()); |
| | | productDto.setWidth(product.getWidth()); |
| | | productDto.setHeight(product.getHeight()); |
| | | productDto.setQuantity(product.getQuantity()); |
| | | productDto.setSettlePieceArea(product.getSettlePieceArea()); |
| | | productDto.setSettleTotalArea(product.getSettleTotalArea()); |
| | | productDto.setTaxInclusiveUnitPrice(product.getTaxInclusiveUnitPrice()); |
| | | productDto.setTaxRate(product.getTaxRate()); |
| | | productDto.setTaxInclusiveTotalPrice(product.getTaxInclusiveTotalPrice()); |
| | | productDto.setTaxExclusiveTotalPrice(product.getTaxExclusiveTotalPrice()); |
| | | productDto.setInvoiceType(product.getInvoiceType()); |
| | | productDto.setProcessRequirement(product.getProcessRequirement()); |
| | | productDto.setRemark(product.getRemark()); |
| | | productExportList.add(productDto); |
| | | } |
| | | } |
| | | |
| | | // 3. 使用ExcelUtil导出(内部会创建Workbook并写入响应) |
| | | // 先创建临时文件,再合并两个sheet |
| | | response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); |
| | | response.setCharacterEncoding("utf-8"); |
| | | String fileName = URLEncoder.encode("销售台账.xlsx", "utf-8").replaceAll("\\+", "%20"); |
| | | response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName); |
| | | |
| | | org.apache.poi.xssf.usermodel.XSSFWorkbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(); |
| | | |
| | | // Sheet1: 销售台账 - 手动填充 |
| | | fillSheetWithData(workbook, "销售台账", SalesLedgerExportDto.class, ledgerExportList); |
| | | |
| | | // Sheet2: 产品明细 - 手动填充 |
| | | fillSheetWithData(workbook, "产品明细", SalesLedgerProductExportDto.class, productExportList); |
| | | |
| | | workbook.write(response.getOutputStream()); |
| | | workbook.close(); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("导出销售台账失败", e); |
| | | throw new ServiceException("导出失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void exportProcessRoute(HttpServletResponse response, List<Long> salesLedgerIds, String completedTimeStart, String completedTimeEnd) { |
| | | try { |
| | | if (CollectionUtils.isEmpty(salesLedgerIds)) { |
| | | throw new ServiceException("请选择要导出的销售台账"); |
| | | } |
| | | LocalDateTime startTime = parseCompletedTime(completedTimeStart); |
| | | LocalDateTime endTime = parseCompletedTime(completedTimeEnd); |
| | | if (startTime == null && endTime == null) { |
| | | startTime = LocalDate.now().atStartOfDay(); |
| | | endTime = LocalDateTime.now(); |
| | | } else { |
| | | if (startTime == null) { |
| | | startTime = LocalDate.now().atStartOfDay(); |
| | | } |
| | | if (endTime == null) { |
| | | endTime = LocalDateTime.now(); |
| | | } |
| | | } |
| | | |
| | | LambdaQueryWrapper<SalesLedgerProcessRouteRecord> queryWrapper = Wrappers.<SalesLedgerProcessRouteRecord>lambdaQuery() |
| | | .eq(SalesLedgerProcessRouteRecord::getIsCompleted, 1) |
| | | .ge(SalesLedgerProcessRouteRecord::getCompletedTime, startTime) |
| | | .le(SalesLedgerProcessRouteRecord::getCompletedTime, endTime) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getCompletedTime) |
| | | .orderByAsc(SalesLedgerProcessRouteRecord::getId); |
| | | |
| | | if (CollectionUtils.isNotEmpty(salesLedgerIds)) { |
| | | queryWrapper.in(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerIds); |
| | | } |
| | | |
| | | List<SalesLedgerProcessRouteRecord> completedRoutes = salesLedgerProcessRouteRecordService.list(queryWrapper); |
| | | Map<Long, SalesLedger> salesLedgerMap = Collections.emptyMap(); |
| | | Map<Long, SalesLedgerProcessRoute> routeMap = Collections.emptyMap(); |
| | | Map<Long, ProcessRouteItem> processRouteItemMap = Collections.emptyMap(); |
| | | Map<Long, List<SalesLedgerProduct>> productMap = Collections.emptyMap(); |
| | | |
| | | if (CollectionUtils.isNotEmpty(completedRoutes)) { |
| | | List<Long> routeSalesLedgerIds = completedRoutes.stream() |
| | | .map(SalesLedgerProcessRouteRecord::getSalesLedgerId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | List<Long> salesLedgerProcessRouteIds = completedRoutes.stream() |
| | | .map(SalesLedgerProcessRouteRecord::getSalesLedgerProcessRouteId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isNotEmpty(routeSalesLedgerIds)) { |
| | | salesLedgerMap = salesLedgerMapper.selectBatchIds(routeSalesLedgerIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a)); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>() |
| | | .in(SalesLedgerProduct::getSalesLedgerId, routeSalesLedgerIds) |
| | | .eq(SalesLedgerProduct::getType, 1) |
| | | .orderByAsc(SalesLedgerProduct::getSalesLedgerId) |
| | | .orderByAsc(SalesLedgerProduct::getId)); |
| | | productMap = products.stream().collect(Collectors.groupingBy( |
| | | SalesLedgerProduct::getSalesLedgerId, |
| | | LinkedHashMap::new, |
| | | Collectors.toList() |
| | | )); |
| | | } |
| | | |
| | | if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteIds)) { |
| | | routeMap = salesLedgerProcessRouteService.listByIds(salesLedgerProcessRouteIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, item -> item, (a, b) -> a)); |
| | | List<Long> processRouteItemIds = routeMap.values().stream() |
| | | .map(SalesLedgerProcessRoute::getProcessRouteItemId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isNotEmpty(processRouteItemIds)) { |
| | | processRouteItemMap = processRouteItemMapper.selectBatchIds(processRouteItemIds).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(ProcessRouteItem::getId, item -> item, (a, b) -> a)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Map<Long, List<SalesLedgerProcessRouteRecord>> routeGroupMap = new LinkedHashMap<>(); |
| | | for (SalesLedgerProcessRouteRecord record : completedRoutes) { |
| | | SalesLedgerProcessRoute route = routeMap.get(record.getSalesLedgerProcessRouteId()); |
| | | if (route == null || route.getProcessRouteItemId() == null) { |
| | | continue; |
| | | } |
| | | routeGroupMap.computeIfAbsent(route.getProcessRouteItemId(), k -> new ArrayList<>()).add(record); |
| | | } |
| | | |
| | | final Map<Long, ProcessRouteItem> finalProcessRouteItemMap = processRouteItemMap; |
| | | LinkedHashMap<String, List<List<Object>>> sheetMap = new LinkedHashMap<>(); |
| | | List<Long> orderedProcessRouteItemIds = routeGroupMap.keySet().stream() |
| | | .sorted((left, right) -> compareProcessRouteItem(left, right, finalProcessRouteItemMap)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | for (Long processRouteItemId : orderedProcessRouteItemIds) { |
| | | ProcessRouteItem processRouteItem = finalProcessRouteItemMap.get(processRouteItemId); |
| | | String sheetName = buildUniqueSheetName(sheetMap, processRouteItem, processRouteItemId); |
| | | List<List<Object>> sheetData = new ArrayList<>(); |
| | | sheetData.add(buildProcessRouteHeader()); |
| | | |
| | | for (SalesLedgerProcessRouteRecord route : routeGroupMap.getOrDefault(processRouteItemId, Collections.emptyList())) { |
| | | SalesLedger salesLedger = salesLedgerMap.get(route.getSalesLedgerId()); |
| | | if (salesLedger == null) { |
| | | continue; |
| | | } |
| | | List<SalesLedgerProduct> products = productMap.getOrDefault(salesLedger.getId(), Collections.emptyList()); |
| | | if (CollectionUtils.isEmpty(products)) { |
| | | sheetData.add(buildProcessRouteRow(salesLedger, null, route)); |
| | | continue; |
| | | } |
| | | for (SalesLedgerProduct product : products) { |
| | | sheetData.add(buildProcessRouteRow(salesLedger, product, route)); |
| | | } |
| | | } |
| | | |
| | | if (sheetData.size() == 1) { |
| | | sheetData.add(Arrays.asList("", "", "", "", "", "", "", "", "")); |
| | | } |
| | | sheetMap.put(sheetName, sheetData); |
| | | } |
| | | |
| | | if (sheetMap.isEmpty()) { |
| | | List<List<Object>> sheetData = new ArrayList<>(); |
| | | sheetData.add(buildProcessRouteHeader()); |
| | | sheetData.add(Arrays.asList("", "", "", "", "", "", "")); |
| | | sheetMap.put("工艺路线", sheetData); |
| | | } |
| | | |
| | | com.ruoyi.common.utils.excel.ExcelUtils.exportManySheet(response, "销售台账工艺路线导出", sheetMap); |
| | | } catch (Exception e) { |
| | | log.error("导出售后台账工艺路线失败", e); |
| | | throw new ServiceException("导出售后台账工艺路线失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private LocalDateTime parseCompletedTime(String value) { |
| | | if (!StringUtils.hasText(value)) { |
| | | return null; |
| | | } |
| | | String text = value.trim(); |
| | | try { |
| | | return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); |
| | | } catch (Exception ex) { |
| | | try { |
| | | return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); |
| | | } catch (Exception ignored) { |
| | | return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private int compareProcessRouteItem(Long left, Long right, Map<Long, ProcessRouteItem> processRouteItemMap) { |
| | | ProcessRouteItem leftItem = processRouteItemMap.get(left); |
| | | ProcessRouteItem rightItem = processRouteItemMap.get(right); |
| | | int leftSort = leftItem != null && leftItem.getDragSort() != null ? leftItem.getDragSort() : Integer.MAX_VALUE; |
| | | int rightSort = rightItem != null && rightItem.getDragSort() != null ? rightItem.getDragSort() : Integer.MAX_VALUE; |
| | | if (leftSort != rightSort) { |
| | | return Integer.compare(leftSort, rightSort); |
| | | } |
| | | String leftName = leftItem != null && StringUtils.hasText(leftItem.getProcessName()) ? leftItem.getProcessName() : ""; |
| | | String rightName = rightItem != null && StringUtils.hasText(rightItem.getProcessName()) ? rightItem.getProcessName() : ""; |
| | | int nameCompare = leftName.compareTo(rightName); |
| | | if (nameCompare != 0) { |
| | | return nameCompare; |
| | | } |
| | | return Long.compare(left, right); |
| | | } |
| | | |
| | | private List<Object> buildProcessRouteHeader() { |
| | | return Arrays.asList("日期", "订单编号", "客户名称", "规格", "数量", "面积", "是否是工程"); |
| | | } |
| | | |
| | | private List<Object> buildProcessRouteRow(SalesLedger salesLedger, SalesLedgerProduct product, SalesLedgerProcessRouteRecord route) { |
| | | List<Object> row = new ArrayList<>(); |
| | | row.add(salesLedger.getEntryDate() == null ? "" : DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, salesLedger.getEntryDate())); |
| | | row.add(salesLedger.getSalesContractNo()); |
| | | row.add(salesLedger.getCustomerName()); |
| | | row.add(product == null ? "" : product.getSpecificationModel()); |
| | | row.add(product == null ? "" : product.getQuantity()); |
| | | row.add(product == null ? "" : resolveExportArea(product)); |
| | | row.add(""); |
| | | return row; |
| | | } |
| | | |
| | | private BigDecimal resolveExportArea(SalesLedgerProduct product) { |
| | | if (product == null) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | if (product.getSettleTotalArea() != null) { |
| | | return product.getSettleTotalArea(); |
| | | } |
| | | if (product.getActualTotalArea() != null) { |
| | | return product.getActualTotalArea(); |
| | | } |
| | | BigDecimal qty = product.getQuantity() == null ? BigDecimal.ONE : product.getQuantity(); |
| | | if (product.getSettlePieceArea() != null) { |
| | | return product.getSettlePieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | if (product.getActualPieceArea() != null) { |
| | | return product.getActualPieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | if (product.getWidth() != null && product.getHeight() != null) { |
| | | BigDecimal area = product.getWidth().multiply(product.getHeight()) |
| | | .divide(new BigDecimal("1000000"), 2, RoundingMode.HALF_UP); |
| | | return area.multiply(qty).setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | return BigDecimal.ZERO; |
| | | } |
| | | |
| | | private String buildUniqueSheetName(Map<String, List<List<Object>>> sheetMap, ProcessRouteItem processRouteItem, Long processRouteItemId) { |
| | | String baseName = processRouteItem != null && StringUtils.hasText(processRouteItem.getProcessName()) |
| | | ? processRouteItem.getProcessName() |
| | | : "工序" + processRouteItemId; |
| | | baseName = sanitizeSheetName(baseName); |
| | | String sheetName = baseName; |
| | | int suffix = 2; |
| | | while (sheetMap.containsKey(sheetName)) { |
| | | String suffixText = "_" + suffix++; |
| | | int maxBaseLength = 31 - suffixText.length(); |
| | | String trimmedBase = baseName.length() > maxBaseLength ? baseName.substring(0, maxBaseLength) : baseName; |
| | | sheetName = trimmedBase + suffixText; |
| | | } |
| | | return sheetName; |
| | | } |
| | | |
| | | private String sanitizeSheetName(String sheetName) { |
| | | if (!StringUtils.hasText(sheetName)) { |
| | | return "工艺路线"; |
| | | } |
| | | String sanitized = sheetName.replaceAll("[\\\\/?*\\[\\]:]", "_").trim(); |
| | | if (sanitized.isEmpty()) { |
| | | sanitized = "工艺路线"; |
| | | } |
| | | return sanitized.length() > 31 ? sanitized.substring(0, 31) : sanitized; |
| | | } |
| | | |
| | | /** |
| | | * 手动填充Sheet数据 |
| | | */ |
| | | private <T> void fillSheetWithData(org.apache.poi.xssf.usermodel.XSSFWorkbook workbook, String sheetName, Class<T> clazz, List<T> dataList) throws Exception { |
| | | org.apache.poi.ss.usermodel.Sheet sheet = workbook.createSheet(sheetName); |
| | | |
| | | // 获取字段上的@Excel注解 |
| | | java.lang.reflect.Field[] fields = clazz.getDeclaredFields(); |
| | | List<java.lang.reflect.Field> excelFields = new ArrayList<>(); |
| | | for (java.lang.reflect.Field field : fields) { |
| | | com.ruoyi.framework.aspectj.lang.annotation.Excel excel = field.getAnnotation(com.ruoyi.framework.aspectj.lang.annotation.Excel.class); |
| | | if (excel != null) { |
| | | excelFields.add(field); |
| | | } |
| | | } |
| | | |
| | | // 创建表头 |
| | | org.apache.poi.ss.usermodel.Row headerRow = sheet.createRow(0); |
| | | org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle(); |
| | | headerStyle.setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.GREY_50_PERCENT.getIndex()); |
| | | headerStyle.setFillPattern(org.apache.poi.ss.usermodel.FillPatternType.SOLID_FOREGROUND); |
| | | headerStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER); |
| | | org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont(); |
| | | headerFont.setBold(true); |
| | | headerStyle.setFont(headerFont); |
| | | |
| | | for (int i = 0; i < excelFields.size(); i++) { |
| | | java.lang.reflect.Field field = excelFields.get(i); |
| | | field.setAccessible(true); |
| | | com.ruoyi.framework.aspectj.lang.annotation.Excel excel = field.getAnnotation(com.ruoyi.framework.aspectj.lang.annotation.Excel.class); |
| | | org.apache.poi.ss.usermodel.Cell cell = headerRow.createCell(i); |
| | | cell.setCellValue(excel.name()); |
| | | cell.setCellStyle(headerStyle); |
| | | sheet.setColumnWidth(i, 20 * 256); |
| | | } |
| | | |
| | | // 创建数据行 |
| | | org.apache.poi.ss.usermodel.CellStyle dataStyle = workbook.createCellStyle(); |
| | | dataStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER); |
| | | |
| | | for (int rowIndex = 0; rowIndex < dataList.size(); rowIndex++) { |
| | | T data = dataList.get(rowIndex); |
| | | org.apache.poi.ss.usermodel.Row row = sheet.createRow(rowIndex + 1); |
| | | for (int colIndex = 0; colIndex < excelFields.size(); colIndex++) { |
| | | java.lang.reflect.Field field = excelFields.get(colIndex); |
| | | field.setAccessible(true); |
| | | Object value = field.get(data); |
| | | org.apache.poi.ss.usermodel.Cell cell = row.createCell(colIndex); |
| | | if (value == null) { |
| | | cell.setCellValue(""); |
| | | } else if (value instanceof Number) { |
| | | cell.setCellValue(((Number) value).doubleValue()); |
| | | } else if (value instanceof Date) { |
| | | cell.setCellValue(new java.text.SimpleDateFormat("yyyy-MM-dd").format((Date) value)); |
| | | } else { |
| | | cell.setCellValue(value.toString()); |
| | | } |
| | | cell.setCellStyle(dataStyle); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String getDeliveryStatusText(Integer status) { |
| | | if (status == null) return "未知"; |
| | | switch (status) { |
| | | case 1: return "未发货"; |
| | | case 2: return "审批中"; |
| | | case 3: return "审批不通过"; |
| | | case 4: return "审批通过"; |
| | | case 5: return "已发货"; |
| | | case 6: return "部分发货"; |
| | | default: return "未知"; |
| | | } |
| | | } |
| | | |
| | | private String getStockStatusText(Integer status) { |
| | | if (status == null) return "未知"; |
| | | switch (status) { |
| | | case 0: return "未入库"; |
| | | case 1: return "部分入库"; |
| | | case 2: return "已入库"; |
| | | case 3: return "审批中"; |
| | | default: return "未知"; |
| | | } |
| | | } |
| | | |
| | | private String getReviewStatusText(Integer status) { |
| | | if (status == null) return "待审核"; |
| | | switch (status) { |
| | | case 0: return "待审核"; |
| | | case 1: return "已审核"; |
| | | case 2: return "已反审"; |
| | | default: return "待审核"; |
| | | } |
| | | } |
| | | |
| | | private String getOrderStatusText(Integer status) { |
| | | if (status == null || status == 0) return "进行中"; |
| | | switch (status) { |
| | | case 0: return "进行中"; |
| | | case 1: return "已完成"; |
| | | default: return "进行中"; |
| | | } |
| | | } |
| | | } |