liyong
11 小时以前 74a29854bb8ff92d2ff2fcb55fa5028609ec6a33
采购删除导致审批报错+发货台账导入关联销售台账+生成出库记录
已修改8个文件
190 ■■■■ 文件已修改
src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/WeighingRecordController.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/WeighingRecord.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/IWeighingRecordService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/WeighingRecordServiceImpl.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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;
    }
}