src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
@@ -9,7 +9,8 @@ PRODUCTION_REPORT_STOCK_OUT("3", "生产报工-出库"), SALE_STOCK_OUT("8", "销售-出库"), PURCHASE_RETURN_STOCK_OUT("9", "采购退货"), SALE_SHIP_STOCK_OUT("13", "销售-发货出库"); SALE_SHIP_STOCK_OUT("13", "销售-发货出库"), WEIGHBRIDGE_OUT("33", "磅单出库"); private final String code; private final String value; src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -232,7 +232,7 @@ purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); purchaseLedger.setRecorderName(sysUser.getNickName()); purchaseLedger.setPhoneNumber(sysUser.getPhonenumber()); purchaseLedger.setApprovalStatus(1); purchaseLedger.setApprovalStatus(3); List<SalesLedgerProduct> productList = Optional.ofNullable(purchaseLedgerDto.getProductData()).orElse(Collections.emptyList()); // 3. 新增或更新主表 @@ -849,7 +849,9 @@ if(salesLedger1 != null){ salesLedger.setSalesLedgerId(salesLedger1.getId()); } // 采购审核 // 设置为待审批状态 salesLedger.setApprovalStatus(3); /* // 采购审核 - 已废弃,不再发起审批流程 // 通过昵称获取用户ID String[] split = salesLedger.getApproveUserIds().split(","); List<Long> ids = new ArrayList<>(); @@ -862,7 +864,7 @@ } // 将集合转为字符串,隔开 String collect = ids.stream().map(Object::toString).collect(Collectors.joining(",")); salesLedger.setApproveUserIds(collect); salesLedger.setApproveUserIds(collect); */ purchaseLedgerMapper.insert(salesLedger); for (PurchaseLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) { @@ -933,7 +935,7 @@ salesLedgerProductMapper.insert(salesLedgerProduct); } // 采购审核 addApproveByPurchase(loginUser,salesLedger); // addApproveByPurchase(loginUser,salesLedger); } return AjaxResult.success("导入成功"); src/main/java/com/ruoyi/sales/controller/WeighingRecordController.java
@@ -16,11 +16,14 @@ import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.ArrayList; import java.util.List; import static com.ruoyi.framework.datasource.DynamicDataSourceContextHolder.log; /** * 过磅记录(磅单台账)Controller @@ -74,11 +77,15 @@ // 去重检查 List<WeighingRecord> newRecordList = new ArrayList<>(); int duplicateCount = 0; int matchedCount = 0; int unmatchedCount = 0; for (WeighingRecord record : weighingRecordList) { LambdaQueryWrapper<WeighingRecord> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(WeighingRecord::getSerialNo, record.getSerialNo()); if (ObjectUtils.isEmpty(record.getSpecification())) { record.setSpecification("/"); } long count = weighingRecordService.count(wrapper); if (count == 0) { newRecordList.add(record); @@ -91,13 +98,33 @@ return R.fail("所有数据都已存在,共" + duplicateCount + "条重复数据"); } // 批量插入新数据 weighingRecordService.saveBatch(newRecordList); // 批量插入新数据并执行出库操作 for (WeighingRecord record : newRecordList) { // 先保存磅单记录,获取ID weighingRecordService.save(record); String message = String.format("导入成功:%d条,跳过重复:%d条", newRecordList.size(), duplicateCount); // 根据客户、产品名称、规格匹配销售台账并出库 Long productId = weighingRecordService.matchAndOutStock( record.getReceiveUnit(), // 收货单位=客户 record.getGoodsName(), // 货名=产品名称 record.getSpecification(), // 规格型号 record.getNetWeight(), // 净重=数量 record.getId() // 磅单ID作为关联记录ID ); if (productId != null) { matchedCount++; } else { unmatchedCount++; } } String message = String.format("导入成功:%d条,跳过重复:%d条,匹配出库:%d条,未匹配:%d条", newRecordList.size(), duplicateCount, matchedCount, unmatchedCount); return R.ok(message); } catch (Exception e) { log.error("磅单导入失败:{}", e.getMessage()); return R.fail("导入失败:" + e.getMessage()); } } src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -12,7 +12,6 @@ import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Date; /** * 产品信息对象 sales_ledger_product @@ -206,7 +205,7 @@ @Excel(name = "发货日期", width = 30, dateFormat = "yyyy-MM-dd") @TableField(exist = false) @JsonFormat(pattern = "yyyy-MM-dd") private Date shippingDate; private LocalDateTime shippingDate; @TableField(exist = false) @ApiModelProperty(value = "发货状态") src/main/java/com/ruoyi/sales/pojo/WeighingRecord.java
@@ -87,4 +87,7 @@ @ApiModelProperty(value = "租户ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; private Long recordId; } src/main/java/com/ruoyi/sales/service/IWeighingRecordService.java
@@ -5,6 +5,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.sales.pojo.WeighingRecord; import java.math.BigDecimal; public interface IWeighingRecordService extends IService<WeighingRecord> { IPage<WeighingRecord> listPage(Page<WeighingRecord> page, WeighingRecord weighingRecord); Long matchAndOutStock(String receiveUnit, String goodsName, String specification, BigDecimal netWeight, Long id); } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -27,7 +27,9 @@ import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.ShippingInfo; import com.ruoyi.sales.pojo.WeighingRecord; import com.ruoyi.sales.service.ISalesLedgerProductService; import com.ruoyi.sales.service.IWeighingRecordService; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import lombok.AllArgsConstructor; @@ -88,13 +90,14 @@ private StockUtils stockUtils; @Autowired private ProductStructureMapper productStructureMapper; @Autowired private StockInventoryMapper stockInventoryMapper; @Autowired private ProductOrderServiceImpl productOrderServiceImpl; @Autowired private IWeighingRecordService iWeighingRecordService; @Override public SalesLedgerProduct selectSalesLedgerProductById(Long id) { @@ -107,20 +110,23 @@ // queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerProduct.getSalesLedgerId()) // .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType()); List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct); if(!CollectionUtils.isEmpty(salesLedgerProducts)){ if (!CollectionUtils.isEmpty(salesLedgerProducts)) { salesLedgerProducts.forEach(item -> { // 发货信息 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getSalesLedgerProductId, item.getId()) .orderByDesc(ShippingInfo::getCreateTime) .last("limit 1")); if(shippingInfo != null){ item.setShippingDate(shippingInfo.getShippingDate()); item.setShippingCarNumber(shippingInfo.getShippingCarNumber()); item.setShippingStatus(shippingInfo.getStatus()); item.setExpressCompany(shippingInfo.getExpressCompany()); item.setExpressNumber(shippingInfo.getExpressNumber()); List<WeighingRecord> list = iWeighingRecordService.list(new QueryWrapper<WeighingRecord>().lambda().eq(WeighingRecord::getRecordId, item.getId()).orderByDesc(WeighingRecord::getCreateTime)); if (!list.isEmpty()) { BigDecimal reduce = list.stream().map(WeighingRecord::getNetWeight).collect(Collectors.toList()).stream().reduce(BigDecimal.ZERO, BigDecimal::add); item.setShippingDate(list.get(0).getSecondWeighTime()); item.setShippingCarNumber(list.get(0).getCarNo()); if (reduce.compareTo(BigDecimal.ZERO) == 0) { item.setShippingStatus("未发货"); } else if (reduce.compareTo(item.getQuantity()) < 0) { item.setShippingStatus("部分发货"); } else { item.setShippingStatus("已发货"); } } item.setShippingStatus("未发货"); }); // 开票 InvoiceRegistrationProductDto invoiceRegistrationProductDto = new InvoiceRegistrationProductDto(); @@ -134,8 +140,8 @@ BigDecimal noInvoiceNum = BigDecimal.ZERO; BigDecimal noInvoiceAmount = BigDecimal.ZERO; for (InvoiceRegistrationProductDto registrationProductDto : invoiceRegistrationProductDtoList) { if(ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()){ invoiceNum = invoiceNum.add(registrationProductDto.getInvoiceNum()); if (ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()) { invoiceNum = invoiceNum.add(registrationProductDto.getInvoiceNum()); invoiceAmount = invoiceAmount.add(registrationProductDto.getInvoiceAmount()); } } @@ -169,7 +175,7 @@ //删除发货信息 List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>() .in(ShippingInfo::getSalesLedgerProductId, Arrays.asList(ids))); if(!CollectionUtils.isEmpty(shippingInfos)){ if (!CollectionUtils.isEmpty(shippingInfos)) { shippingInfoService.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList())); } @@ -296,12 +302,12 @@ BigDecimal ticketsTotal = salesLedgerProduct.getTicketsTotal() != null ? salesLedgerProduct.getTicketsTotal() : BigDecimal.ZERO; // 待回款,付款 if(salesLedgerProduct.getType().equals(1)){ if (salesLedgerProduct.getType().equals(1)) { salesLedgerProduct.setPendingInvoiceTotal(totalPrice.subtract(invoiceTotal)); //未开票数量+金额 salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); salesLedgerProduct.setNoInvoiceAmount(totalPrice); }else{ } else { salesLedgerProduct.setPendingTicketsTotal(totalPrice.subtract(ticketsTotal)); // 未来票数量+金额 salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity()); @@ -376,7 +382,7 @@ List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda() .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()) .orderByDesc(ProcessRoute::getCreateTime)); if (processRoutes.size()>0){ if (processRoutes.size() > 0) { ProcessRoute processRoute = processRoutes.get(0); //新增生产订单工艺路线主表 ProductProcessRoute productProcessRoute = new ProductProcessRoute(); @@ -413,7 +419,7 @@ } } // 生成完整的工单号 String workOrderNoStr ="GD"+ String.format("%s%03d", datePrefix, sequenceNumber); String workOrderNoStr = "GD" + String.format("%s%03d", datePrefix, sequenceNumber); ProductWorkOrder productWorkOrder = new ProductWorkOrder(); productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId()); productWorkOrder.setProductOrderId(productOrder.getId()); @@ -434,7 +440,7 @@ * 删除生产数据 */ public void deleteProductionData(List<Long> productIds) { if (productIds == null || productIds.isEmpty()){ if (productIds == null || productIds.isEmpty()) { return; } //批量查询productOrder @@ -533,9 +539,9 @@ // 判断状态 BigDecimal taxInclusiveTotalPrice = item.getTaxInclusiveTotalPrice(); BigDecimal invoiceTotal = item.getInvoiceTotal(); if(taxInclusiveTotalPrice != null && invoiceTotal != null && taxInclusiveTotalPrice.compareTo(invoiceTotal) == 0){ if (taxInclusiveTotalPrice != null && invoiceTotal != null && taxInclusiveTotalPrice.compareTo(invoiceTotal) == 0) { item.setStatusName("已完成付款"); }else{ } else { item.setStatusName("未完成付款"); } }); @@ -549,9 +555,9 @@ // 判断状态 BigDecimal taxInclusiveTotalPrice = item.getTaxInclusiveTotalPrice(); BigDecimal ticketsTotal = item.getTicketsTotal(); if(taxInclusiveTotalPrice != null && ticketsTotal != null && taxInclusiveTotalPrice.compareTo(ticketsTotal) == 0){ if (taxInclusiveTotalPrice != null && ticketsTotal != null && taxInclusiveTotalPrice.compareTo(ticketsTotal) == 0) { item.setStatusName("已完成付款"); }else{ } else { item.setStatusName("未完成付款"); } }); @@ -592,6 +598,7 @@ throw new RuntimeException("动态更新主表金额失败", e); } } @Override public R judgmentInventory(SalesLedgerProduct salesLedgerProduct) { //获取产品最新的工艺路线 @@ -610,7 +617,7 @@ //所需数量 BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity()); BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING); BigDecimal subtract = stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING); if (subtract.compareTo(BigDecimal.ZERO) <= 0) { count++; stringBuffer.append(productStructureDto.getProductName()) @@ -621,9 +628,9 @@ .append(System.lineSeparator()); } } if (count>0) { if (count > 0) { return R.fail(stringBuffer.toString()); }else { } else { return R.ok(); } } src/main/java/com/ruoyi/sales/service/impl/WeighingRecordServiceImpl.java
@@ -4,13 +4,22 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.WeighingRecordMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.WeighingRecord; import com.ruoyi.sales.service.IWeighingRecordService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; @Service @Slf4j @@ -18,6 +27,9 @@ public class WeighingRecordServiceImpl extends ServiceImpl<WeighingRecordMapper, WeighingRecord> implements IWeighingRecordService { private final WeighingRecordMapper weighingRecordMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final SalesLedgerMapper salesLedgerMapper; private final StockUtils stockUtils; @Override public IPage<WeighingRecord> listPage(Page<WeighingRecord> page, WeighingRecord weighingRecord) { @@ -43,4 +55,63 @@ WeighingRecord::getShipUnit, weighingRecord.getShipUnit()); return weighingRecordMapper.selectPage(page, queryWrapper); } /** * 根据客户、产品名称、规格型号匹配销售台账产品并出库 * @param receiveUnit 收货单位(客户名称) * @param goodsName 货名(产品名称) * @param specification 规格 * @param quantity 数量(净重) * @param recordId 磅单记录ID(作为关联记录ID) * @return 匹配到的销售台账产品ID,未匹配返回null */ public Long matchAndOutStock(String receiveUnit, String goodsName, String specification, BigDecimal quantity, Long recordId) { // 1. 查询所有销售台账产品(只查询未发货的) LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SalesLedgerProduct::getType, 1); // 销售类型 List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper); if (productList == null || productList.isEmpty()) { log.warn("未找到未发货的销售台账产品数据"); return null; } // 2. 遍历匹配:客户名称 + 产品大类 + 规格型号 for (SalesLedgerProduct product : productList) { // 获取对应的销售台账主表信息 SalesLedger salesLedger = salesLedgerMapper.selectById(product.getSalesLedgerId()); if (salesLedger == null) { continue; } // 匹配条件:收货单位=客户名称,货名=产品大类,规格=规格型号 boolean customerMatch = receiveUnit != null && receiveUnit.equals(salesLedger.getCustomerName()); boolean goodsMatch = goodsName != null && goodsName.equals(product.getProductCategory()); boolean specMatch = specification != null && specification.equals(product.getSpecificationModel()); if (customerMatch && goodsMatch && specMatch) { // 3. 匹配成功,执行出库 try { WeighingRecord weighingRecord = new WeighingRecord(); weighingRecord.setRecordId(product.getId()); weighingRecord.setId(recordId); this.updateById(weighingRecord); stockUtils.substractStock( product.getProductModelId(), quantity, StockOutQualifiedRecordTypeEnum.WEIGHBRIDGE_OUT.getCode(), // 磅单出库类型 recordId // 磅单ID作为关联记录ID ); log.info("磅单出库成功:客户={}, 产品={}, 规格={}, 数量={}, 磅单ID={}", receiveUnit, goodsName, specification, quantity, recordId); return product.getId(); } catch (Exception e) { log.error("磅单出库失败:{}", e.getMessage()); throw new RuntimeException("出库失败:" + e.getMessage()); } } } log.warn("未匹配到销售台账产品:客户={}, 产品={}, 规格={}", receiveUnit, goodsName, specification); return null; } }