liyong
8 天以前 6f287ccb0f8df857fbce894bd241cdf77690cecb
Merge branch 'jtwy' of http://114.132.189.42:9002/r/product-inventory-management-after into sqd-hb
已添加2个文件
已修改33个文件
799 ■■■■■ 文件已修改
doc/20260119-procurement_record_storage.sql 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/ProductModel.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionProgressDto.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionTurnoverDto.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementAddDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordStorage.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductBomController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/SalesLedgerProductionAccountingController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProcessRouteService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java 144 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 175 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/ProductModelMapper.xml 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductStructureMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductInputMapper.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260119-procurement_record_storage.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2 @@
alter table procurement_record_storage
    add quality_inspect_id bigint null comment '质检id';
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
import org.apache.ibatis.annotations.Param;
@@ -17,6 +18,8 @@
    IPage<ProductModel> listPageProductModel(Page<ProductModel> page, @Param("c") ProductModel productModel);
    IPage<ProductModel> listPageProductionStock(Page<ProductModel> page, @Param("req") ProcurementPageDto req);
    ProductModel selectLatestRecord();
}
src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -6,6 +6,7 @@
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("product_model")
@@ -59,4 +60,7 @@
    @TableField(exist = false)
    @Excel(name = "剩余库存")
    private BigDecimal stockQuantity;
    @TableField(exist = false)
    private LocalDateTime createTime;
}
src/main/java/com/ruoyi/home/dto/ProductionProgressDto.java
@@ -12,14 +12,14 @@
@ApiModel
public class ProductionProgressDto {
    @ApiModelProperty("总订单数")
    private Integer totalOrderCount;
    private Long totalOrderCount;
    @ApiModelProperty("已完成订单数")
    private Integer completedOrderCount;
    private Long completedOrderCount;
    @ApiModelProperty("未完成订单数")
    private Integer uncompletedOrderCount;
    @ApiModelProperty("总体完成进度")
    private BigDecimal completedProgressCount;
    private Long uncompletedOrderCount;
    @ApiModelProperty("部分完成订单数")
    private Long partialCompletedOrderCount;
    @ApiModelProperty("订单详情")
    private List<ProductOrderDto> completedOrderDetails;
}
src/main/java/com/ruoyi/home/dto/ProductionTurnoverDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.home.dto;
import com.ruoyi.production.dto.ProductOrderDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@ApiModel
public class ProductionTurnoverDto {
    @ApiModelProperty("总在制数量")
    private Long totalOrderCount;
    @ApiModelProperty("平均周转天数")
    private BigDecimal averageTurnoverDays;
    @ApiModelProperty("周转效率")
    private BigDecimal turnoverEfficiency;
    @ApiModelProperty("工序详情")
    private List<String> processDetails;
    @ApiModelProperty("工序对应的数量详情")
    private List<Long> processQuantityDetails;
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
@@ -235,8 +235,8 @@
    @GetMapping("/listPageProductionStock")
    @Log(title = "库存管理-成品库存", businessType = BusinessType.OTHER)
    public AjaxResult listPageProductionStock(Page page) {
        IPage<ProductModel> result = procurementRecordService.listPageProductionStock(page);
    public AjaxResult listPageProductionStock(Page page, ProcurementPageDto procurementDto) {
        IPage<ProductModel> result = procurementRecordService.listPageProductionStock(page,procurementDto);
        return AjaxResult.success(result);
    }
}
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementAddDto.java
@@ -22,6 +22,7 @@
    private String typeName;
    private Integer purchaseLedgerId;
    private Long qualityInspectId;
    private Long qualityInspectId;
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordStorage.java
@@ -101,6 +101,5 @@
     */
    private Long productModelId;
    private Long qualityInspectId;
}
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
@@ -60,7 +60,7 @@
    BigDecimal getProcurementAmount(Long salesProductId);
    InventoryInformationDto getReportList();
    IPage<ProductModel> listPageProductionStock(Page page);
    IPage<ProductModel> listPageProductionStock(Page page, ProcurementPageDto procurementDto);
    IPage<ProcurementPageDto> listPageByProductProduction(Page page, ProcurementPageDto procurementDto);
}
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -885,15 +885,8 @@
    }
    @Override
    public IPage<ProductModel> listPageProductionStock(Page page) {
        ProductModel productModel = new ProductModel();
        IPage<ProductModel> iPage = productModelMapper.listPageProductModel(page, productModel);
        iPage.getRecords().forEach(item -> {
            item.setInboundNum(stockUtils.getStockQuantity(item.getId()).get("inboundNum"));
            item.setOutboundNum(stockUtils.getStockQuantity(item.getId()).get("outboundNum"));
            item.setStockQuantity(stockUtils.getStockQuantity(item.getId()).get("stockQuantity"));
        });
        return iPage;
    public IPage<ProductModel> listPageProductionStock(Page page, ProcurementPageDto dto) {
        return productModelMapper.listPageProductionStock(page, dto);
    }
src/main/java/com/ruoyi/production/controller/ProductBomController.java
@@ -9,10 +9,12 @@
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductBom;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessRouteService;
import com.ruoyi.production.service.ProductProcessService;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.service.ProductionProductMainService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -12,6 +13,7 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
@RequestMapping("productionProductMain")
src/main/java/com/ruoyi/production/controller/SalesLedgerProductionAccountingController.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.pojo.AccountExpense;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.service.impl.SalesLedgerProductionAccountingServiceImpl;
import io.swagger.annotations.Api;
src/main/java/com/ruoyi/production/service/ProcessRouteService.java
@@ -8,6 +8,8 @@
import java.util.List;
import java.util.List;
public interface ProcessRouteService extends IService<ProcessRoute> {
    IPage<ProcessRouteDto> pageProcessRouteDto(Page<ProcessRouteDto> page, ProcessRouteDto processRouteDto);
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java
@@ -8,9 +8,14 @@
import com.ruoyi.production.mapper.ProcessRouteItemMapper;
import com.ruoyi.production.mapper.ProcessRouteMapper;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductProcessRouteMapper;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.ruoyi.production.service.ProcessRouteService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -20,6 +25,8 @@
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Arrays;
import java.util.List;
@Service
@AllArgsConstructor
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -32,6 +32,8 @@
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import oshi.driver.mac.net.NetStat;
import java.math.BigDecimal;
import java.time.LocalDate;
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
@@ -24,6 +25,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -192,14 +194,26 @@
     */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, PurchaseLedgerDto purchaseLedger) {
        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = purchaseLedgerService.selectPurchaseLedgerListPage(page ,purchaseLedger);
        //过滤掉approvalStatus=3的记录
        purchaseLedgerDtoIPage.getRecords().removeIf(purchaseLedgerDto -> purchaseLedgerDto.getApprovalStatus() == 3);
        purchaseLedgerDtoIPage.getRecords().forEach(purchaseLedgerDto -> {
            if (purchaseLedgerDto.getUnReceiptPaymentAmount().compareTo(BigDecimal.ZERO) == 0) {
                purchaseLedgerDto.setUnReceiptPaymentAmount(purchaseLedgerDto.getContractAmount());
        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = Optional.ofNullable(
                purchaseLedgerService.selectPurchaseLedgerListPage(page, purchaseLedger)
        ).orElse(new Page<>());
        // å¤„理null
        Optional.ofNullable(purchaseLedgerDtoIPage.getRecords())
                .filter(CollectionUtils::isNotEmpty)
                .ifPresent(records -> {
                    // è¿‡æ»¤approvalStatus=3的记录
                    records.removeIf(dto -> dto != null && dto.getApprovalStatus() == 3);
                    // ä¿®æ­£æœªæ”¶ä»˜æ¬¾é‡‘额
                    records.forEach(dto -> {
                        if (dto == null) return;
                        BigDecimal unReceiptAmt = Optional.ofNullable(dto.getUnReceiptPaymentAmount()).orElse(BigDecimal.ZERO);
                        if (unReceiptAmt.compareTo(BigDecimal.ZERO) == 0) {
                            dto.setUnReceiptPaymentAmount(Optional.ofNullable(dto.getContractAmount()).orElse(BigDecimal.ZERO));
            }
        });
                });
         return AjaxResult.success(purchaseLedgerDtoIPage);
    }
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -24,6 +24,8 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
@@ -111,6 +113,7 @@
    private final QualityTestStandardMapper qualityTestStandardMapper;
    private final QualityInspectParamMapper qualityInspectParamMapper;
    private final ProcurementRecordMapper procurementRecordStorageMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
@@ -238,10 +241,12 @@
            handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
        }
        //新增原材料检验
        if (productList != null) {
        for (SalesLedgerProduct saleProduct : productList) {
            //是否推送质检,如果true就添加
            if (saleProduct.getIsChecked()) {
                addQualityInspect(purchaseLedger, saleProduct);
                }
            }
        }
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
@@ -256,8 +261,8 @@
        QualityInspect qualityInspect = new QualityInspect();
        qualityInspect.setInspectType(0);
        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
        qualityInspect.setProductId(saleProduct.getId());
        qualityInspect.setPurchaseLedgerId(saleProduct.getId());
        qualityInspect.setProductId(saleProduct.getProductId());
        qualityInspect.setProductName(saleProduct.getProductCategory());
        qualityInspect.setModel(saleProduct.getSpecificationModel());
        qualityInspect.setProductModelId(saleProduct.getProductModelId());
@@ -445,6 +450,19 @@
        if (ids == null || ids.length == 0) {
           throw new BaseException("请选中至少一条数据");
        }
        // æ‰¹é‡åˆ é™¤å…³è”的采购入库记录
        LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductQueryWrapper = new LambdaQueryWrapper<>();
        salesLedgerProductQueryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids)
                .eq(SalesLedgerProduct::getType, 2);
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(salesLedgerProductQueryWrapper);
        if (CollectionUtils.isNotEmpty(salesLedgerProducts)) {
            salesLedgerProducts.stream().forEach(salesLedgerProduct -> {
                // æ‰¹é‡åˆ é™¤å…³è”的采购台账产品
                LambdaQueryWrapper<ProcurementRecordStorage> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ProcurementRecordStorage::getSalesLedgerProductId, salesLedgerProduct.getId());
                procurementRecordStorageMapper.delete(queryWrapper);
            });
        }
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账产品
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids)
src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.purchase.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
@@ -29,6 +30,7 @@
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import lombok.RequiredArgsConstructor;
@@ -48,10 +50,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
@@ -163,6 +162,14 @@
                    productRecord.setPurchaseLedgerId(ticketRegistrationDto.getPurchaseLedgerId());
                    productRecord.setCreatedAt(DateUtils.getNowDate());
                    BeanUtils.copyProperties(salesLedgerProduct, productRecord);
                    //同步更新其他剩余数量和金额
                    productRecordMapper.update(
                            null,
                            new LambdaUpdateWrapper<ProductRecord>()
                                    .eq(ProductRecord::getPurchaseLedgerId, ticketRegistrationDto.getPurchaseLedgerId())
                                    .set(ProductRecord::getFutureTickets, salesLedgerProduct.getFutureTickets())
                                    .set(ProductRecord::getFutureTicketsAmount, salesLedgerProduct.getFutureTicketsAmount())
                    );
                    productRecord.setSaleLedgerProjectId(salesLedgerProduct.getId());
                    productRecord.setId(null);
                    productRecord.setType("2");
@@ -249,50 +256,119 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delRegistration(Long[] ids) {
        // åˆ é™¤é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•对象
        LambdaQueryWrapper<ProductRecord> productRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        productRecordLambdaQueryWrapper.in(ProductRecord::getId, Arrays.asList(ids));
        List<ProductRecord> productRecords = productRecordMapper.selectList(productRecordLambdaQueryWrapper);
        //  æŸ¥è¯¢è¦åˆ é™¤çš„产品来票记录
        LambdaQueryWrapper<ProductRecord> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.in(ProductRecord::getId, Arrays.asList(ids));
        List<ProductRecord> productRecords = productRecordMapper.selectList(productWrapper);
        if(CollectionUtils.isEmpty(productRecords)){
            return 0;
        }
        LambdaQueryWrapper<TicketRegistration> ticketRegistrationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        ticketRegistrationLambdaQueryWrapper.in(TicketRegistration::getId, productRecords.stream().map(ProductRecord::getTicketRegistrationId).collect(Collectors.toList()));
        List<TicketRegistration> ticketRegistrations = ticketRegistrationMapper.selectList(ticketRegistrationLambdaQueryWrapper);
        // ä¿®æ”¹äº§å“ä¿¡æ¯
        for (ProductRecord productRecord : productRecords) {
            BigDecimal subtract = ticketRegistrations.get(0).getInvoiceAmount().subtract(productRecords.get(0).getTicketsAmount());
            // å°äºŽç­‰äºŽ0删除 ï¼Œå¤§äºŽ0修改
            if(subtract.compareTo(BigDecimal.ZERO) <= 0){
                ticketRegistrationMapper.deleteById(ticketRegistrations.get(0));
                // åˆ é™¤ä»˜æ¬¾æµæ°´è®°å½•
                paymentRegistrationMapper.delete(new LambdaQueryWrapper<PaymentRegistration>().eq(PaymentRegistration::getTicketRegistrationId, ticketRegistrations.get(0).getId()));
            }else if(subtract.compareTo(BigDecimal.ZERO) > 0){
                ticketRegistrations.get(0).setInvoiceAmount(subtract);
                ticketRegistrationMapper.updateById(ticketRegistrations.get(0));
        //  æ”¶é›†å…³è”ID
        Set<Long> ticketRegistrationIds = productRecords.stream()
                .map(ProductRecord::getTicketRegistrationId)
                .collect(Collectors.toSet());
        Set<Long> salesLedgerProductIds = productRecords.stream()
                .map(ProductRecord::getSaleLedgerProjectId)
                .collect(Collectors.toSet());
        //  æŸ¥è¯¢æ¥ç¥¨ç™»è®°
        List<TicketRegistration> ticketRegistrations =
                ticketRegistrationMapper.selectBatchIds(ticketRegistrationIds);
        //  å¤„理来票登记金额、付款流水
        for (TicketRegistration ticket : ticketRegistrations) {
            // è¯¥æ¥ç¥¨ç™»è®°ä¸‹æ‰€æœ‰äº§å“è®°å½•
            List<ProductRecord> recordsOfTicket = productRecords.stream()
                    .filter(r -> r.getTicketRegistrationId().equals(ticket.getId()))
                    .collect(Collectors.toList());
            // è®¡ç®—要回退的金额
            BigDecimal rollbackAmount = recordsOfTicket.stream()
                    .map(ProductRecord::getTicketsAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal remain = ticket.getInvoiceAmount().subtract(rollbackAmount);
            if (remain.compareTo(BigDecimal.ZERO) <= 0) {
                // åˆ é™¤æ¥ç¥¨ç™»è®°
                ticketRegistrationMapper.deleteById(ticket.getId());
                // åˆ é™¤ä»˜æ¬¾æµæ°´
                paymentRegistrationMapper.delete(
                        new LambdaQueryWrapper<PaymentRegistration>()
                                .eq(PaymentRegistration::getTicketRegistrationId, ticket.getId())
                );
            } else {
                ticket.setInvoiceAmount(remain);
                ticketRegistrationMapper.updateById(ticket);
            }
            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductLambdaQueryWrapper = new LambdaQueryWrapper<>();
            salesLedgerProductLambdaQueryWrapper.eq(SalesLedgerProduct::getId, productRecord.getSaleLedgerProjectId())
        }
        //  å›žé€€é”€å”®å°è´¦äº§å“çš„æœªæ¥ç¥¨
        for (ProductRecord record : productRecords) {
            LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SalesLedgerProduct::getId, record.getSaleLedgerProjectId())
                    .eq(SalesLedgerProduct::getType, 2);
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(salesLedgerProductLambdaQueryWrapper);
            if(!CollectionUtils.isEmpty(salesLedgerProducts)){
                for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
                    salesLedgerProduct.setFutureTickets(salesLedgerProduct.getFutureTickets().add(productRecord.getTicketsNum()));
                    salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getFutureTicketsAmount().add(productRecord.getTicketsAmount()));
                    salesLedgerProduct.setTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getFutureTicketsAmount()));
                    salesLedgerProduct.setTicketsNum(salesLedgerProduct.getQuantity().subtract(salesLedgerProduct.getFutureTickets()));
                    salesLedgerProductMapper.updateById(salesLedgerProduct);
            SalesLedgerProduct product = salesLedgerProductMapper.selectOne(wrapper);
            if (product != null) {
                product.setFutureTickets(
                        product.getFutureTickets().add(record.getTicketsNum())
                );
                product.setFutureTicketsAmount(
                        product.getFutureTicketsAmount().add(record.getTicketsAmount())
                );
                salesLedgerProductMapper.updateById(product);
                }
            }
        //  åˆ é™¤äº§å“æ¥ç¥¨è®°å½•
        productRecordMapper.delete(productWrapper);
        //  é‡æ–°è®¡ç®— currentInvoiceAmount
        for (Long productId : salesLedgerProductIds) {
            refreshCurrentInvoiceAmount(productId);
        }
        // åˆ é™¤é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•
        productRecordMapper.delete(productRecordLambdaQueryWrapper);
        return 1;
    }
    private void refreshCurrentInvoiceAmount(Long salesLedgerProductId) {
        // æŸ¥è¯¢è¯¥äº§å“æœ€æ–°ä¸€æ¡æ¥ç¥¨è®°å½•
        LambdaQueryWrapper<ProductRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductRecord::getSaleLedgerProjectId, salesLedgerProductId)
                .orderByDesc(ProductRecord::getCreatedAt)
                .last("limit 1");
        ProductRecord latestRecord = productRecordMapper.selectOne(wrapper);
        SalesLedgerProduct product =
                salesLedgerProductMapper.selectById(salesLedgerProductId);
        if (product == null) {
            return;
        }
        if (latestRecord == null) {
            //  æ²¡æœ‰ä»»ä½•来票记录
            product.setTicketsAmount(BigDecimal.ZERO);
        } else {
            //  æ°¸è¿œå–最新一条
            product.setTicketsAmount(latestRecord.getTicketsAmount());
        }
        salesLedgerProductMapper.updateById(product);
    }
    @Override
    public TicketRegistrationDto getRegistrationById(TicketRegistrationDto ticketRegistrationDto) {
        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(ticketRegistrationDto.getId());
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -3,6 +3,9 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.service.impl.ProcurementRecordServiceImpl;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
@@ -12,6 +15,7 @@
import com.ruoyi.quality.service.IQualityInspectParamService;
import com.ruoyi.quality.service.IQualityInspectService;
import com.ruoyi.quality.service.IQualityUnqualifiedService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -34,6 +38,8 @@
    @Resource
    private IQualityInspectFileService qualityInspectFileService;
    @Autowired
    private ProcurementRecordService procurementRecordService;
    /**
@@ -62,6 +68,8 @@
        //删除检验附件
        qualityInspectFileService.remove(Wrappers.<QualityInspectFile>lambdaQuery()
        .in(QualityInspectFile::getInspectId,ids));
        //删除入库记录
        procurementRecordService.remove(Wrappers.<ProcurementRecordStorage>lambdaQuery().in(ProcurementRecordStorage::getQualityInspectId,ids));
        //删除检验单
        return AjaxResult.success(qualityInspectService.removeBatchByIds(ids));
    }
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -138,6 +138,7 @@
     */
    private Integer inspectState;
    //采购台账产品id
    private Long purchaseLedgerId;
    /**
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -98,6 +98,8 @@
    public int submit(QualityInspect inspect) {
        QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId());
        /*判断不合格*/
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtils.isNotNull(qualityInspect.getCheckResult()) && qualityInspect.getCheckResult().equals("不合格")){
            QualityUnqualified qualityUnqualified = new QualityUnqualified();
            BeanUtils.copyProperties(qualityInspect,qualityUnqualified);
@@ -106,20 +108,19 @@
            String text = inspectParams.stream().map(QualityInspectParam::getParameterItem).collect(Collectors.joining(","));
            qualityUnqualified.setDefectivePhenomena(text+"这些指标中存在不合格");//不合格现象
            qualityUnqualifiedMapper.insert(qualityUnqualified);
        }
        } else {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (qualityInspect.getInspectType() == 0) {
            if ("合格".equals(qualityInspect.getCheckResult())) {
                ProcurementAddDto procurementRecordOutAdd = new ProcurementAddDto();
                procurementRecordOutAdd.setType(1);
                procurementRecordOutAdd.setTypeName("采购入库");
                    procurementRecordOutAdd.setTypeName("采购原材料检验合格入库");
                procurementRecordOutAdd.setNickName(loginUser.getNickName());
                procurementRecordOutAdd.setPurchaseLedgerId(Math.toIntExact(qualityInspect.getPurchaseLedgerId()));
                if (qualityInspect.getPurchaseLedgerId() == null) {
                    throw new BaseException("请选择采购单");
                }
                SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(qualityInspect.getProductId());
                    SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(qualityInspect.getPurchaseLedgerId());
                ArrayList<Details> detailss = new ArrayList<>();
                Details details = new Details();
@@ -131,13 +132,14 @@
                details.setProductModelId(qualityInspect.getProductModelId());
                detailss.add( details);
                procurementRecordOutAdd.setDetails(detailss);
                    procurementRecordOutAdd.setQualityInspectId(qualityInspect.getId());
                procurementRecordService.add(procurementRecordOutAdd);
            }
        }else if (qualityInspect.getInspectType() == 1) {
            //查询UnitPrice/TotalPrice
            ProcurementAddDto procurementRecordOutAdd = new ProcurementAddDto();
            procurementRecordOutAdd.setType(2);
            procurementRecordOutAdd.setTypeName("生产入库");
                procurementRecordOutAdd.setTypeName("生产过程检验合格入库");
            procurementRecordOutAdd.setNickName(loginUser.getNickName());
            List<Details> details = new ArrayList<>();
            Details details1 = new Details();
@@ -158,9 +160,9 @@
                    .updateTime(LocalDateTime.now())
                    .updateUser(loginUser.getUserId())
                    .createBy(procurementRecordOutAdd.getNickName())
                    .productModelId(details1.getProductModelId());
                        .productModelId(details1.getProductModelId())
                        .qualityInspectId(qualityInspect.getId());
            procurementRecordService.save(procurementRecordBuilder.build());
        }else if (qualityInspect.getInspectType() == 2) {
@@ -168,7 +170,7 @@
            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectSalesLedgerProductByMainId(qualityInspect.getProductMainId());
            ProcurementAddDto procurementRecordOutAdd = new ProcurementAddDto();
            procurementRecordOutAdd.setType(2);
            procurementRecordOutAdd.setTypeName("生产入库");
                procurementRecordOutAdd.setTypeName("生产出厂检验合格入库");
            procurementRecordOutAdd.setNickName(loginUser.getNickName());
            List<Details> details = new ArrayList<>();
            Details details1 = new Details();
@@ -179,8 +181,11 @@
            details1.setProductModelId(salesLedgerProduct.getProductModelId());
            details.add(details1);
            procurementRecordOutAdd.setDetails(details);
                procurementRecordOutAdd.setQualityInspectId(qualityInspect.getId());
            procurementRecordService.add(procurementRecordOutAdd);
        }
        }
        qualityInspect.setInspectState(1);//已提交
        return qualityInspectMapper.updateById(qualityInspect);
    }
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -65,7 +65,7 @@
            BigDecimal stockQuantity = stockUtils.getStockQuantity(item.getProductModelId()).get("stockQuantity");
            if(stockQuantity != null) {
//                ProcurementPageDtoCopy procurementDtoCopy = result.getRecords().get(0);
                if (item.getQuantity().compareTo(stockQuantity) >= 0 && item.getApproveStatus() == 0) {
                if (item.getQuantity().compareTo(stockQuantity) <= 0 && item.getApproveStatus() == 0) {
                    item.setApproveStatus(1);
                    salesLedgerProductService.addOrUpdateSalesLedgerProduct(item);
                }
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.math.LongMath;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.controller.BaseController;
@@ -88,20 +89,22 @@
        //  å®¡æ‰¹é€šè¿‡
        if (req.getApproveStatus() == 3) {
            // æŸ¥è¯¢é‡‡è´­å…¥åº“记录
            LambdaQueryWrapper<ProcurementRecordStorage> lambdaQueryWrapper = new LambdaQueryWrapper<ProcurementRecordStorage>()
                    .eq(ProcurementRecordStorage::getSalesLedgerProductId, req.getSalesLedgerProductId());
            ProcurementRecordStorage procurementRecordStorage = procurementRecordStorageService.getOne(lambdaQueryWrapper);
            if (procurementRecordStorage == null) {
                // ä¿è¯å‰é¢çš„修改全部回滚
                throw new ServiceException("采购记录不存在,审批回滚");
            }
//            // æŸ¥è¯¢é‡‡è´­å…¥åº“记录
//            LambdaQueryWrapper<ProcurementRecordStorage> lambdaQueryWrapper = new LambdaQueryWrapper<ProcurementRecordStorage>()
//                    .eq(ProcurementRecordStorage::getSalesLedgerProductId, req.getSalesLedgerProductId());
//            ProcurementRecordStorage procurementRecordStorage = procurementRecordStorageService.getOne(lambdaQueryWrapper);
//
//            if (procurementRecordStorage == null) {
//                // ä¿è¯å‰é¢çš„修改全部回滚
//                throw new ServiceException("采购记录不存在,审批回滚");
//            }
            //  ç”Ÿæˆå‡ºåº“记录
            ProcurementRecordOutAdd procurementRecordOutAdd = new ProcurementRecordOutAdd();
            procurementRecordOutAdd.setId(procurementRecordStorage.getId());
            procurementRecordOutAdd.setSalesLedgerProductId(salesLedgerProduct.getId());
//            procurementRecordOutAdd.setId(procurementRecordStorage.getId());
            procurementRecordOutAdd.setId(0);
            procurementRecordOutAdd.setProductModelId(salesLedgerProduct.getProductModelId());
            procurementRecordOutAdd.setSalesLedgerProductId((long) Math.toIntExact(salesLedgerProduct.getId()));
            procurementRecordOutAdd.setType(2);
            procurementRecordOutAdd.setUserId(Math.toIntExact(getUserId()));
            procurementRecordOutAdd.setQuantity(salesLedgerProduct.getQuantity().toPlainString());
src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -70,6 +72,13 @@
                invoiceAmountTotal = invoiceAmountTotal.add(currentInvoiceNum);
                InvoiceRegistrationProduct invoiceRegistrationProduct = new InvoiceRegistrationProduct();
                BeanUtils.copyProperties(productDatum, invoiceRegistrationProduct);
                //更新已开票剩余未开票数
                invoiceRegistrationProductMapper.update(
                        null,
                        new LambdaUpdateWrapper<InvoiceRegistrationProduct>()
                                .eq(InvoiceRegistrationProduct::getSalesLedgerId, salesLedgerDto.getId())
                                .set(InvoiceRegistrationProduct::getNoInvoiceAmount, productDatum.getNoInvoiceAmount())
                );
                invoiceRegistrationProduct.setId(null);
                invoiceRegistrationProduct.setSalesLedgerId(salesLedgerDto.getId().intValue());
                invoiceRegistrationProduct.setInvoiceRegistrationId(invoiceRegistration.getId());
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -3,11 +3,14 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
@@ -42,6 +45,7 @@
public class SalesLedgerProductServiceImpl extends ServiceImpl<SalesLedgerProductMapper, SalesLedgerProduct> implements ISalesLedgerProductService {
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private SalesLedgerMapper salesLedgerMapper;
@@ -59,6 +63,10 @@
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
    private ProductionProductInputMapper productionProductInputMapper;
    private QualityInspectMapper qualityInspectMapper;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -87,10 +95,10 @@
                        if(ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()){
                            invoiceNum =  invoiceNum.add(registrationProductDto.getInvoiceNum());
                            invoiceAmount = invoiceAmount.add(registrationProductDto.getInvoiceAmount());
                        }
                    }
                            noInvoiceNum = ledgerProduct.getQuantity().subtract(invoiceNum);
                            noInvoiceAmount = ledgerProduct.getTaxInclusiveTotalPrice().subtract(invoiceAmount);
                        }
                    }
                    ledgerProduct.setInvoiceNum(invoiceNum);
                    ledgerProduct.setInvoiceAmount(invoiceAmount);
                    ledgerProduct.setNoInvoiceNum(noInvoiceNum);
@@ -193,6 +201,54 @@
        if (salesLedgerProduct.getId() == null) {
            salesLedgerProduct.setRegisterDate(LocalDateTime.now());
            result = salesLedgerProductMapper.insert(salesLedgerProduct);
            addProductionData(salesLedgerProduct);
        } else {
            //查询原本的产品型号id
            salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
            result = salesLedgerProductMapper.updateById(salesLedgerProduct);
            /*删除对应的生产数据并重新新增*/
            deleteProductionData(Arrays.asList(salesLedgerProduct.getId()));
            // åˆ é™¤ç”Ÿäº§æ ¸ç®—数据
            LambdaQueryWrapper<SalesLedgerProductionAccounting> reportWrapper = new LambdaQueryWrapper<>();
            reportWrapper.in(SalesLedgerProductionAccounting::getSalesLedgerId, salesLedgerId);
            salesLedgerProductionAccountingMapper.delete(reportWrapper);
            addProductionData(salesLedgerProduct);
        }
        // å¦‚果插入或更新成功,并且有 salesLedgerId,才继续更新主表金额
        if (result > 0 && salesLedgerId != null) {
            // æŸ¥è¯¢è¯¥ä¸»è¡¨ä¸‹çš„æ‰€æœ‰å­è¡¨æ•°æ®
            LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)
                    .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
            List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(wrapper);
            if (salesLedgerProduct.getType() == 1) {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        salesLedgerMapper,
                        SalesLedger.class
                );
            } else {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        purchaseLedgerMapper,
                        PurchaseLedger.class
                );
            }
        }
        return result;
    }
    /**
     * æ–°å¢žç”Ÿäº§æ•°æ®
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
            ProductOrder productOrder = new ProductOrder();
            productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
            productOrder.setProductModelId(salesLedgerProduct.getId());
@@ -201,8 +257,11 @@
            productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
            productOrderMapper.insert(productOrder);
            ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()));
            if (processRoute != null) {
        List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda()
                .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId())
                .orderByDesc(ProcessRoute::getCreateTime));
        if (processRoutes.size()>0){
            ProcessRoute processRoute = processRoutes.get(0);
                //新增生产订单工艺路线主表
                ProductProcessRoute productProcessRoute = new ProductProcessRoute();
                productProcessRoute.setProductModelId(processRoute.getProductModelId());
@@ -220,6 +279,7 @@
                    productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                    productProcessRouteItem.setProductOrderId(productOrder.getId());
                    productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
                    int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                    if (insert > 0) {
                        // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
@@ -258,41 +318,90 @@
                productOrder.setRouteId(processRoute.getId());
                productOrderMapper.updateById(productOrder);
            }
        } else {
            salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
            result = salesLedgerProductMapper.updateById(salesLedgerProduct);
        }
        // å¦‚果插入或更新成功,并且有 salesLedgerId,才继续更新主表金额
        if (result > 0 && salesLedgerId != null) {
            // æŸ¥è¯¢è¯¥ä¸»è¡¨ä¸‹çš„æ‰€æœ‰å­è¡¨æ•°æ®
            LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)
                    .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
            List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(wrapper);
            if (salesLedgerProduct.getType() == 1) {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        salesLedgerMapper,
                        SalesLedger.class
    /**
     * åˆ é™¤ç”Ÿäº§æ•°æ®
     */
    public void deleteProductionData(List<Long> productIds) {
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getProductModelId, productIds)
                );
            } else {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        purchaseLedgerMapper,
                        PurchaseLedger.class
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            List<Long> orderIds = productOrders.stream()
                    .map(ProductOrder::getId)
                    .collect(Collectors.toList());
            // æ‰¹é‡æŸ¥è¯¢processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
                );
            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(allRouteItems)) {
                // èŽ·å–è¦åˆ é™¤çš„å·¥åºé¡¹ID
                List<Long> routeItemIds = allRouteItems.stream()
                        .map(ProductProcessRouteItem::getId)
                        .collect(Collectors.toList());
                // æŸ¥è¯¢å…³è”的工单ID
                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
                        new LambdaQueryWrapper<ProductWorkOrder>()
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
                );
                if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(workOrders)) {
                    List<Long> workOrderIds = workOrders.stream()
                            .map(ProductWorkOrder::getId)
                            .collect(Collectors.toList());
                    // æŸ¥è¯¢å…³è”的生产主表ID
                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                            new LambdaQueryWrapper<ProductionProductMain>()
                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
                    );
                    List<Long> productMainIds = productMains.stream()
                            .map(ProductionProductMain::getId)
                            .collect(Collectors.toList());
                    // åˆ é™¤äº§å‡ºè¡¨ã€æŠ•入表数据
                    if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(productMainIds)) {
                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                                new LambdaQueryWrapper<QualityInspect>()
                                        .in(QualityInspect::getProductMainId, productMainIds)
                        );
                        qualityInspects.forEach(qualityInspect -> {
                            //inspectState=1 å·²æäº¤ ä¸èƒ½åˆ é™¤
                            if (qualityInspect.getInspectState() == 1) {
                                throw new RuntimeException("已提交的检验单不能删除");
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                    }
                    // åˆ é™¤ç”Ÿäº§ä¸»è¡¨æ•°æ®
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // åˆ é™¤å·¥å•数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
            }
        }
        return result;
            // æ‰¹é‡åˆ é™¤processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getProductModelId, productIds));
        }
    }
    /**
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -32,6 +32,7 @@
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import com.ruoyi.sales.service.ISalesLedgerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -77,6 +78,7 @@
    private final CustomerMapper customerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
    private final CommonFileMapper commonFileMapper;
@@ -178,7 +180,7 @@
    @Override
    public List<Map<String, Object>> getSalesNo() {
        LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(SalesLedger::getId, SalesLedger::getSalesContractNo, SalesLedger::getProjectName);
        queryWrapper.select(SalesLedger::getId, SalesLedger::getSalesContractNo);
        // èŽ·å–åŽŸå§‹æŸ¥è¯¢ç»“æžœ
        List<Map<String, Object>> result = salesLedgerMapper.selectMaps(queryWrapper);
@@ -393,86 +395,8 @@
        List<Long> productIds = products.stream()
                .map(SalesLedgerProduct::getId)
                .collect(Collectors.toList());
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getProductModelId, productIds)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            List<Long> orderIds = productOrders.stream()
                    .map(ProductOrder::getId)
                    .collect(Collectors.toList());
            // æ‰¹é‡æŸ¥è¯¢processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
            );
            if (!CollectionUtils.isEmpty(allRouteItems)) {
                // èŽ·å–è¦åˆ é™¤çš„å·¥åºé¡¹ID
                List<Long> routeItemIds = allRouteItems.stream()
                        .map(ProductProcessRouteItem::getId)
                        .collect(Collectors.toList());
                // æŸ¥è¯¢å…³è”的工单ID
                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
                        new LambdaQueryWrapper<ProductWorkOrder>()
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
                );
                if (!CollectionUtils.isEmpty(workOrders)) {
                    List<Long> workOrderIds = workOrders.stream()
                            .map(ProductWorkOrder::getId)
                            .collect(Collectors.toList());
                    // æŸ¥è¯¢å…³è”的生产主表ID
                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                            new LambdaQueryWrapper<ProductionProductMain>()
                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
                    );
                    List<Long> productMainIds = productMains.stream()
                            .map(ProductionProductMain::getId)
                            .collect(Collectors.toList());
                    // åˆ é™¤äº§å‡ºè¡¨ã€æŠ•入表数据
                    if (!CollectionUtils.isEmpty(productMainIds)) {
                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                                new LambdaQueryWrapper<QualityInspect>()
                                        .in(QualityInspect::getProductMainId, productMainIds)
                        );
                        qualityInspects.forEach(qualityInspect -> {
                            //inspectState=1 å·²æäº¤ ä¸èƒ½åˆ é™¤
                            if(qualityInspect.getInspectState() == 1){
                                throw new RuntimeException("已提交的检验单不能删除");
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                    }
                    // åˆ é™¤ç”Ÿäº§ä¸»è¡¨æ•°æ®
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // åˆ é™¤å·¥å•数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
                }
            }
            // æ‰¹é‡åˆ é™¤processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getProductModelId, productIds));
        }
        //删除生产数据
        salesLedgerProductServiceImpl.deleteProductionData(productIds);
        // æ‰¹é‡åˆ é™¤äº§å“å­è¡¨
        if (!productIds.isEmpty()) {
@@ -512,7 +436,7 @@
        LambdaQueryWrapper<SalesLedgerWork> workOrderWrapper = new LambdaQueryWrapper<>();
        workOrderWrapper.in(SalesLedgerWork::getSalesLedgerId, idList);
        salesLedgerWorkMapper.delete(workOrderWrapper);
        // åˆ é™¤ç”Ÿäº§æŠ¥å·¥æ•°æ®
        // åˆ é™¤ç”Ÿäº§æ ¸ç®—数据
        LambdaQueryWrapper<SalesLedgerProductionAccounting> reportWrapper = new LambdaQueryWrapper<>();
        reportWrapper.in(SalesLedgerProductionAccounting::getSalesLedgerId, idList);
        salesLedgerProductionAccountingMapper.delete(reportWrapper);
@@ -693,73 +617,8 @@
                salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
                salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProductMapper.insert(salesLedgerProduct);
                ProductOrder productOrder = new ProductOrder();
                productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
                productOrder.setProductModelId(salesLedgerProduct.getId());
                productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
                productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
                productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
                productOrderMapper.insert(productOrder);
                ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()));
                if (processRoute != null) {
                    //新增生产订单工艺路线主表
                    ProductProcessRoute productProcessRoute = new ProductProcessRoute();
                    productProcessRoute.setProductModelId(processRoute.getProductModelId());
                    productProcessRoute.setProcessRouteCode(processRoute.getProcessRouteCode());
                    productProcessRoute.setProductOrderId(productOrder.getId());
                    productProcessRoute.setBomId(processRoute.getBomId());
                    productProcessRouteMapper.insert(productProcessRoute);
                    //新增生产订单工艺路线子表
                    List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
                    // ç”Ÿæˆå½“前日期的前缀:年月日
                    String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                    for (ProcessRouteItem processRouteItem : processRouteItems) {
                        ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                        productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
                        productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                        productProcessRouteItem.setProductOrderId(productOrder.getId());
                        productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                        productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
                        int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                        if (insert > 0) {
                            // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
                            QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                            queryWrapper.likeRight("work_order_no", datePrefix)
                                    .orderByDesc("work_order_no")
                                    .last("LIMIT 1");
                            ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
                            int sequenceNumber = 1; // é»˜è®¤åºå·
                            if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                                String lastNo = lastWorkOrder.getWorkOrderNo().toString();
                                if (lastNo.startsWith(datePrefix)) {
                                    String seqStr = lastNo.substring(datePrefix.length());
                                    try {
                                        sequenceNumber = Integer.parseInt(seqStr) + 1;
                                    } catch (NumberFormatException e) {
                                        sequenceNumber = 1;
                                    }
                                }
                            }
                            // ç”Ÿæˆå®Œæ•´çš„工单号
                            String workOrderNoStr = String.format("%s%03d", datePrefix, sequenceNumber);
                            ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                            if (Objects.equals(productProcessRouteItem.getProductModelId(), salesLedgerProduct.getProductModelId())) {
                                productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                            }
                            productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                            productWorkOrder.setProductOrderId(productOrder.getId());
                            productWorkOrder.setWorkOrderNo(workOrderNoStr);
                            productWorkOrder.setStatus(1);
                            productWorkOrderMapper.insert(productWorkOrder);
                        }
                    }
                    productOrder.setRouteId(processRoute.getId());
                    productOrderMapper.updateById(productOrder);
                }
                // æ·»åŠ ç”Ÿäº§æ•°æ®
                salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
            }
        }
    }
src/main/resources/application-dev.yml
@@ -63,9 +63,9 @@
    druid:
      # ä¸»åº“数据源
      master:
        url: jdbc:mysql://localhost:3306/product-inventory-management-hckx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        url: jdbc:mysql://114.132.189.42:9099/product-inventory-management-sqd?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: 123456
        password: xd@123456..
      # ä»Žåº“数据源
      slave:
        # ä»Žæ•°æ®æºå¼€å…³/默认关闭
@@ -143,7 +143,7 @@
    database: 0
    # å¯†ç 
    #    password: root2022!
    password:
    password: 123456
    # è¿žæŽ¥è¶…æ—¶æ—¶é—´
    timeout: 10s
src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -33,5 +33,68 @@
            LIMIT 1
    </select>
    <select id="listPageProductionStock" resultType="com.ruoyi.basic.pojo.ProductModel">
        SELECT
        pm.id,
        pm.product_id,
        pm.model,
        pm.unit,
        p.product_name,
        GREATEST(s.last_in_time, o.last_out_time) AS create_time,
        COALESCE(s.inboundNum, 0) AS inboundNum,
        COALESCE(o.outboundNum, 0) AS outboundNum,
        COALESCE(s.inboundNum, 0) - COALESCE(o.outboundNum, 0) AS stockQuantity
        FROM product_model pm
        LEFT JOIN product p ON pm.product_id = p.id
        -- å…¥åº“汇总
        LEFT JOIN (
        SELECT
        product_model_id,
        SUM(inbound_num) AS inboundNum,
        MAX(create_time) AS last_in_time
        FROM procurement_record_storage
        <where>
            <if test="req.timeStr != null and req.timeStr != ''">
                AND create_time &gt;= #{req.timeStr}
                AND create_time &lt; DATE_ADD(#{req.timeStr}, INTERVAL 1 DAY)
            </if>
        </where>
        GROUP BY product_model_id
        ) s ON s.product_model_id = pm.id
        -- å‡ºåº“汇总
        LEFT JOIN (
        SELECT
        product_model_id,
        SUM(inbound_num) AS outboundNum,
        MAX(create_time) AS last_out_time
        FROM procurement_record_out
        <where>
            <if test="req.timeStr != null and req.timeStr != ''">
                AND create_time &gt;= #{req.timeStr}
                AND create_time &lt; DATE_ADD(#{req.timeStr}, INTERVAL 1 DAY)
            </if>
        </where>
        GROUP BY product_model_id
        ) o ON o.product_model_id = pm.id
        <where>
            <if test="req.timeStr != null and req.timeStr != ''">
                AND (s.product_model_id IS NOT NULL OR o.product_model_id IS NOT NULL)
            </if>
            <if test="req.productCategory != null and req.productCategory != ''">
                AND EXISTS (
                SELECT 1
                FROM sales_ledger_product slp
                WHERE slp.product_id = p.id
                AND slp.product_category LIKE CONCAT('%', #{req.productCategory}, '%')
                )
            </if>
        </where>
        ORDER BY pm.id DESC
    </select>
</mapper>
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -371,6 +371,7 @@
    <select id="listPageByProductProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
        select
        t1.*,
        t1.inbound_num as inboundNum0,
        t2.model as specification_model  ,
        t2.unit,
        t3.product_name as product_category
src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -43,6 +43,9 @@
            <if test="c.specificationModel != null and c.specificationModel != ''">
                and slp.specification_model like concat('%',#{c.specificationModel},'%')
            </if>
            <if test="c.startTime != null and c.endTime != null">
                and po.create_time between #{c.startTime} and #{c.endTime}
            </if>
        </where>
    </select>
    <select id="productMainByOrderId" resultType="com.ruoyi.production.dto.ProductOrderDto">
src/main/resources/mapper/production/ProductStructureMapper.xml
@@ -25,7 +25,7 @@
        where ps.bom_id = #{bomId}
        order by ps.id
    </select>
    <select id="listByproductModelId" resultType="com.ruoyi.production.dto.ProductStructureDto">
    <select id="listBybomAndProcess" resultType="com.ruoyi.production.dto.ProductStructureDto">
        select ps.*,
               p.product_name,
               pp.name as  process_name,
@@ -33,11 +33,11 @@
               pm.model
        from
            product_structure ps
                left join product_bom pb on ps.bom_id = pb.id
                left join product_model pm on ps.product_model_id = pm.id
                left join product p on pm.product_id = p.id
                left join product_process pp on ps.process_id = pp.id
        where pb.product_model_id = #{productModelId}
        where ps.bom_id = #{bomId}
        and ps.process_id=#{processId}
        order by ps.id
    </select>
    <select id="listBybomAndProcess" resultType="com.ruoyi.production.dto.ProductStructureDto">
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -38,33 +38,9 @@
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
                pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
            </if>
            <if test="c.planStartTime != null and c.planEndTime != null">
                and DATE(pwo.create_time) between #{c.planStartTime} and #{c.planEndTime}
            </if>
        </where>
    </select>
    <select id="selectProductWorkOrderDtoList" resultType="com.ruoyi.production.dto.ProductWorkOrderDto">
        select *
        from product_work_order pwo
        left join product_order po on po.id = pwo.product_order_id
    </select>
    <update id="updatePlanQuantity" parameterType="java.util.Map">
        UPDATE product_work_order
        SET
            report_work = #{reportWork},
            plan_quantity = plan_quantity - #{deductQuantity}
        WHERE id = #{workOrderId}
    </update>
    <update id="rollbackPlanQuantity" parameterType="java.lang.Long">
        UPDATE product_work_order pwo
        INNER JOIN production_product_main ppm
        ON pwo.id = ppm.work_order_id
        AND ppm.id = #{productMainId}
        INNER JOIN production_product_output ppo
        ON ppo.product_main_id = ppm.id
        SET
        pwo.plan_quantity = pwo.plan_quantity + ppo.quantity,
        pwo.report_work = 0,
        pwo.quantity = 0
        WHERE pwo.id = ppm.work_order_id
    </update>
</mapper>
src/main/resources/mapper/production/ProductionProductInputMapper.xml
@@ -13,11 +13,14 @@
    <select id="listPageProductionProductInputDto" resultType="com.ruoyi.production.dto.ProductionProductInputDto">
        select ppi.*,
        pm.model as model,
        ppm.product_no as productNo
        ppm.product_no as productNo,
        p.product_name,
        pm.unit
        from
        production_product_input ppi
        left join production_product_main ppm on ppm.id = ppi.product_main_id
        left join product_model pm on pm.id = ppi.product_model_id
        left join product p on p.id = pm.product_id
        <where>
            <if test="c.productMainId != null and c.productMainId > 0">
                and ppm.id = #{c.productMainId}
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -16,10 +16,20 @@
        select ppm.*,
               pwo.work_order_no as workOrderNo,
               pwo.status as workOrderStatus,
               u.nick_name as nickName
               u.nick_name as nickName,
               p.product_name as productName,
               pm.model as productModelName,
               ppo.quantity,
               pm.unit,
               sl.sales_contract_no salesContractNo
        from
            production_product_main ppm
                left join product_work_order pwo on pwo.id = ppm.work_order_id
                left join product_order po on po.id = pwo.product_order_id
                left join production_product_output ppo on ppm.id = ppo.product_main_id
                left join product_model pm on pm.id = ppo.product_model_id
                left join product p on p.id = pm.product_id
                left join sales_ledger sl on sl.id = po.sales_ledger_id
                left join sys_user u on u.user_id = ppm.user_id
        <where>
            <if test="c.nickName != null and c.nickName != ''">
@@ -36,6 +46,7 @@
            </if>
        </where>
        order by ppm.id
    </select>
    <delete id="deleteByWorkOrderIds" parameterType="java.util.List">