Merge remote-tracking branch 'origin/dev_宁夏_中盛建材' into dev_宁夏_中盛建材
已添加1个文件
已修改11个文件
420 ■■■■ 文件已修改
doc/宁夏-中盛建材.sql 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrder.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/controller/ProductionPlanController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanDto.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanSummaryDto.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/enums/DataSourceTypeEnum.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/mapper/ProductionPlanMapper.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/pojo/ProductionPlan.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/service/ProductionPlanService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/productionPlan/ProductionPlanMapper.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/ÄþÏÄ-ÖÐÊ¢½¨²Ä.sql
@@ -82,3 +82,15 @@
    `update_user` int NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) COMMENT = '能源类型-能耗抄表明细_附件';
alter table product_order
drop column sales_ledger_id,
drop column sale_ledger_product_id,
drop column product_model_id;
alter table production_plan
    add assigned_quantity DECIMAL(10, 4) default 0 not null COMMENT '下发数量';
alter table product_order
    add plan_complete_time datetime(0) NULL DEFAULT NULL COMMENT '计划完成时间',
    add combine_production_plan_ids varchar(500) default '' not null;
src/main/java/com/ruoyi/production/pojo/ProductOrder.java
@@ -11,6 +11,7 @@
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
@TableName("product_order")
@@ -20,24 +21,6 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * é”€å”®å°è´¦id
     */
    @ApiModelProperty(value = "销售台账id")
    private Long salesLedgerId;
    /**
     * é”€å”®å°è´¦äº§å“id(sales_ledger_product)
     */
    @ApiModelProperty(value = "销售台账产品id")
    private Long saleLedgerProductId;
    /**
     * äº§å“è§„æ ¼id
     */
    @ApiModelProperty(value = "产品规格id")
    private Long productModelId;
    /**
     * æ¨¡ç‰ˆçš„工艺路线id
@@ -51,6 +34,20 @@
    @ApiModelProperty(value = "生产订单号")
    @Excel(name = "生产订单号")
    private String npsNo;
    /**
     * åˆå¹¶ç”Ÿäº§è®¡åˆ’ids
     */
    @ApiModelProperty(value = "合并生产计划ids")
    private String combineProductionPlanIds;
    /**
     * è®¡åˆ’完成时间
     */
    @ApiModelProperty(value = "计划完成时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime planCompleteTime;
    /**
     * ç§Ÿæˆ·id
@@ -73,7 +70,6 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    /**
     * éœ€æ±‚数量
@@ -100,7 +96,4 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endTime;
}
src/main/java/com/ruoyi/productionPlan/controller/ProductionPlanController.java
@@ -5,14 +5,15 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.productionPlan.dto.ProductionPlanDto;
import com.ruoyi.productionPlan.dto.ProductionPlanSummaryDto;
import com.ruoyi.productionPlan.service.ProductionPlanService;
import com.ruoyi.staff.dto.StaffLeaveDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <br>
@@ -38,9 +39,32 @@
    }
    @GetMapping("/loadProdData")
    @ApiOperation("拉取销售生产计划")
    @Log(title = "拉取销售生产计划", businessType = BusinessType.INSERT)
    public AjaxResult loadProdData() {
        productionPlanService.loadProdData();
        return AjaxResult.success();
    }
    @PostMapping("/combine")
    @Log(title = "合并生产计划", businessType = BusinessType.INSERT)
    @ApiOperation("合并生产计划")
    public AjaxResult combine(@RequestBody ProductionPlanDto productionPlanDto) {
        return AjaxResult.success(productionPlanService.combine(productionPlanDto));
    }
    @PostMapping("")
    @Log(title = "创建生产计划", businessType = BusinessType.INSERT)
    @ApiOperation("创建生产计划")
    public AjaxResult add(@RequestBody ProductionPlanDto productionPlanDto) {
        return AjaxResult.success(productionPlanService.add(productionPlanDto));
    }
    @GetMapping("/summaryByProductType")
    @ApiOperation("按照产品类别汇总统计需求量")
    @Log(title = "按照产品类别汇总统计需求量", businessType = BusinessType.OTHER)
    public AjaxResult summaryByProductType(ProductionPlanSummaryDto query) {
        List<ProductionPlanSummaryDto> list = productionPlanService.summaryByProductType(query);
        return AjaxResult.success(list);
    }
}
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanDto.java
@@ -1,6 +1,26 @@
package com.ruoyi.productionPlan.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.productionPlan.pojo.ProductionPlan;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class ProductionPlanDto extends ProductionPlan {
    @ApiModelProperty(value = "生产计划id集合")
    private List<Long> ids;
    @ApiModelProperty(value = "下发数量")
    private BigDecimal totalAssignedQuantity;
    @ApiModelProperty(value = "计划完成时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime planCompleteTime;
}
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanSummaryDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package com.ruoyi.productionPlan.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * <br>
 * é”€å”®ç”Ÿäº§éœ€æ±‚ - äº§å“ç±»åž‹æ±‡æ€»DTO
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/03/11 10:24
 */
@Data
@ApiModel("生产需求产品汇总")
public class ProductionPlanSummaryDto {
    /**
     * ç‰©æ–™ç¼–码
     */
    @ApiModelProperty("物料编码")
    private String materialCode;
    /**
     * äº§å“åç§°
     */
    @ApiModelProperty("产品名称")
    private String productName;
    /**
     * äº§å“è§„æ ¼
     */
    @ApiModelProperty("产品规格")
    private String productSpec;
    /**
     * äº§å“é•¿åº¦
     */
    @ApiModelProperty("产品长度")
    private Integer length;
    /**
     * äº§å“å®½åº¦
     */
    @ApiModelProperty("产品宽度")
    private Integer width;
    /**
     * äº§å“é«˜åº¦
     */
    @ApiModelProperty("产品高度")
    private Integer height;
    /**
     * æ±‡æ€»å—æ•°
     */
    @ApiModelProperty("汇总块数")
    private Integer quantity;
    /**
     * æ±‡æ€»æ–¹æ•°
     */
    @ApiModelProperty("汇总方数")
    private BigDecimal volume;
}
src/main/java/com/ruoyi/productionPlan/enums/DataSourceTypeEnum.java
@@ -14,8 +14,8 @@
@Getter
public enum DataSourceTypeEnum {
    SALES_ORDER(1, "销售订单"),
    PRODUCTION_FORECAST(2, "生产预测");
    SALES_ORDER(1, "同步"),
    PRODUCTION_FORECAST(2, "新增");
    private final Integer code;
    private final String desc;
src/main/java/com/ruoyi/productionPlan/mapper/ProductionPlanMapper.java
@@ -4,9 +4,11 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.productionPlan.dto.ProductionPlanDto;
import com.ruoyi.productionPlan.dto.ProductionPlanSummaryDto;
import com.ruoyi.productionPlan.pojo.ProductionPlan;
import com.ruoyi.staff.dto.StaffLeaveDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <br>
@@ -19,4 +21,7 @@
 */
public interface ProductionPlanMapper extends BaseMapper<ProductionPlan> {
    IPage<ProductionPlanDto> listPage(Page page, @Param("c") ProductionPlanDto productionPlanDto);
    List<ProductionPlanSummaryDto> selectSummaryByProductType(ProductionPlanSummaryDto query);
}
src/main/java/com/ruoyi/productionPlan/pojo/ProductionPlan.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@@ -31,146 +32,177 @@
    /**
     * è¡¨å•实例ID
     */
    @ApiModelProperty("表单实例ID")
    private String formInstanceId;
    /**
     * æµæ°´å·
     */
    @ApiModelProperty("流水号")
    private String serialNo;
    /**
     * ç”³è¯·å•编号
     */
    @ApiModelProperty("申请单编号")
    private String applyNo;
    /**
     * å®¢æˆ·åç§°
     */
    @ApiModelProperty("客户名称")
    private String customerName;
    /**
     * ç‰©æ–™ç¼–码
     */
    @ApiModelProperty("物料编码")
    private String materialCode;
    /**
     * äº§å“åç§°
     */
    @ApiModelProperty("产品名称")
    private String productName;
    /**
     * äº§å“è§„æ ¼
     */
    @ApiModelProperty("产品规格")
    private String productSpec;
    /**
     * é•¿
     */
    @ApiModelProperty("长")
    private Integer length;
    /**
     * å®½
     */
    @ApiModelProperty("宽")
    private Integer width;
    /**
     * é«˜
     */
    @ApiModelProperty("高")
    private Integer height;
    /**
     * å—æ•°
     */
    @ApiModelProperty("块数")
    private Integer quantity;
    /**
     * æ–¹æ•°
     */
    @ApiModelProperty("方数")
    private BigDecimal volume;
    /**
     * å¼ºåº¦
     */
    @ApiModelProperty("强度")
    private String strength;
    /**
     * å¼€å§‹æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty("开始日期")
    private LocalDateTime startDate;
    /**
     * ç»“束日期
     */
    @ApiModelProperty("结束日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime endDate;
    /**
     * æäº¤äºº
     */
    @ApiModelProperty("提交人")
    private String submitter;
    /**
     * æäº¤äººç»„织
     */
    @ApiModelProperty("提交人组织")
    private String submitOrg;
    /**
     * å¤‡æ³¨1
     */
    @ApiModelProperty("备注1")
    private String remarkOne;
    /**
     * å¤‡æ³¨2
     */
    @ApiModelProperty("备注2")
    private String remarkTwo;
    /**
     * åˆ›å»ºäºº
     */
    @ApiModelProperty("创建人")
    private String creatorName;
    /**
     * ä¿®æ”¹äºº
     */
    @ApiModelProperty("修改人")
    private String modifierName;
    /**
     * è¡¨å•创建时间
     */
    @ApiModelProperty("表单创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime formCreatedTime;
    /**
     * è¡¨å•修改时间
     */
    @ApiModelProperty("表单修改时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime formModifiedTime;
    /**
     * æ•°æ®åŒæ­¥ç±»åž‹ï¼š1=手动 2=定时任务
     */
    @ApiModelProperty("数据同步类型:1=手动 2=定时任务")
    private Integer dataSyncType;
    /**
     * æ•°æ®æ¥æºç±»åž‹ï¼š1=销售订单 2=销售预测
     * æ•°æ®æ¥æºç±»åž‹ï¼š1=同步 2=新增
     */
    @ApiModelProperty("数据来源类型:1=同步 2=新增")
    private Integer dataSourceType;
    /**
     * æ•°æ®åº“创建时间
     */
    @ApiModelProperty("数据库创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;
    /**
     * æ•°æ®åº“æ›´æ–°æ—¶é—´
     */
    @ApiModelProperty("数据库更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;
    /**
     * å½“前更新数量
     */
    @ApiModelProperty("totalCount")
    private Integer totalCount;
    @ApiModelProperty(value = "下发数量")
    private BigDecimal assignedQuantity;
}
src/main/java/com/ruoyi/productionPlan/service/ProductionPlanService.java
@@ -4,7 +4,10 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.productionPlan.dto.ProductionPlanDto;
import com.ruoyi.productionPlan.dto.ProductionPlanSummaryDto;
import com.ruoyi.productionPlan.pojo.ProductionPlan;
import java.util.List;
/**
 * <br>
@@ -27,4 +30,19 @@
     * å®šæ—¶åŒæ­¥
     */
    void syncProdDataJob();
     /**
     * åˆå¹¶ç”Ÿäº§è®¡åˆ’
     */
    boolean combine(ProductionPlanDto productionPlanDto);
    /**
     * åˆ›å»ºç”Ÿäº§è®¡åˆ’
     */
    boolean add(ProductionPlanDto productionPlanDto);
    /**
     * æŒ‰ç…§äº§å“ç±»åˆ«æ±‡æ€»ç»Ÿè®¡éœ€æ±‚量
     */
    List<ProductionPlanSummaryDto> summaryByProductType(ProductionPlanSummaryDto query);
}
src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java
@@ -7,10 +7,14 @@
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.basic.pojo.Product;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.framework.config.AliDingConfig;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.service.ProductOrderService;
import com.ruoyi.productionPlan.dto.ProductionPlanDto;
import com.ruoyi.productionPlan.dto.ProductionPlanSummaryDto;
import com.ruoyi.productionPlan.mapper.ProductionPlanMapper;
import com.ruoyi.productionPlan.pojo.ProductionPlan;
import com.ruoyi.productionPlan.service.ProductionPlanService;
@@ -19,6 +23,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -26,9 +31,11 @@
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static com.ruoyi.productionPlan.enums.DataSourceTypeEnum.PRODUCTION_FORECAST;
/**
 * <br>
@@ -49,6 +56,9 @@
    @Autowired
    private ProductionPlanMapper productionPlanMapper;
    @Autowired
    private ProductOrderService productOrderService;
    /**
     * åŒæ­¥é”ï¼Œç¡®ä¿æ‰‹åŠ¨å’Œå®šæ—¶ä»»åŠ¡ä¸åŒæ—¶æ‰§è¡Œ
@@ -74,6 +84,83 @@
    @Override
    public void syncProdDataJob() {
        syncProdData(2);
    }
    /**
     * åˆå¹¶ç”Ÿäº§è®¡åˆ’
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean combine(ProductionPlanDto productionPlanDto) {
        if (productionPlanDto.getIds() == null || productionPlanDto.getIds().isEmpty()) {
            return false;
        }
        //  æŸ¥è¯¢ä¸»ç”Ÿäº§è®¡åˆ’
        List<ProductionPlan> plans = productionPlanMapper.selectBatchIds(productionPlanDto.getIds());
        //  æ ¡éªŒæ˜¯å¦å­˜åœ¨ä¸åŒçš„产品名称
        String firstProductName = plans.get(0).getProductName();
        if (plans.stream().anyMatch(p -> !p.getProductName().equals(firstProductName))) {
            log.warn("合并失败,存在不同的产品名称");
            return false;
        }
        // æ ¡éªŒæ˜¯å¦å­˜åœ¨ä¸åŒçš„产品规格
        String firstProductSpec = plans.get(0).getProductSpec();
        if (plans.stream().anyMatch(p -> !p.getProductSpec().equals(firstProductSpec))) {
            log.warn("合并失败,存在不同的产品规格");
            return false;
        }
        // å åŠ æ–¹æ•°
        BigDecimal totalVolume = plans.stream()
                .map(ProductionPlan::getVolume)
                .filter(v -> v != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // åˆ¤æ–­ä¸‹å‘数量是否大于等于方数
        if (productionPlanDto.getTotalAssignedQuantity().compareTo(totalVolume) > 0) {
            log.warn("合并失败,下发数量不能大于方数");
            return false;
        }
        // æ ¹æ®ä¸‹å‘数量,从第一个生产计划开始分配方数
        BigDecimal assignedVolume = BigDecimal.ZERO;
        for (ProductionPlan plan : plans) {
            BigDecimal volume = plan.getVolume();
            if (volume == null) {
                continue;
            }
            if (assignedVolume.add(volume).compareTo(productionPlanDto.getTotalAssignedQuantity()) >= 0) {
                // æœ€åŽä¸€ä¸ªè®¡åˆ’,分配剩余方数
                plan.setAssignedQuantity(productionPlanDto.getTotalAssignedQuantity().subtract(assignedVolume));
                break;
            }
            // åˆ†é…å½“前计划方数
            plan.setAssignedQuantity(volume);
            productionPlanMapper.updateById(plan);
            assignedVolume = assignedVolume.add(volume);
        }
        // åˆ›å»ºç”Ÿäº§è®¢å•
        ProductOrder productOrder = new ProductOrder();
        String combineIds = StringUtils.join(productionPlanDto.getIds(), ",");
        productOrder.setCombineProductionPlanIds(combineIds);
        productOrder.setQuantity(productionPlanDto.getTotalAssignedQuantity());
        productOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime());
        productOrderService.addProductOrder(productOrder);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(ProductionPlanDto productionPlanDto) {
        productionPlanDto.setDataSourceType(PRODUCTION_FORECAST.getCode());
        productionPlanMapper.insert(productionPlanDto);
        return true;
    }
    /**
@@ -133,8 +220,8 @@
                List<ProductionPlan> list = parseProductionPlans(dataArr, dataSyncType, totalCount);
                if (!list.isEmpty()) {
                    //  å¤„理更新或新增
                    processSaveOrUpdate(list);
                    totalSynced += list.size();
                    int affected = processSaveOrUpdate(list);
                    totalSynced += affected;
                }
                //  åˆ¤æ–­æ˜¯å¦è¿˜æœ‰ä¸‹ä¸€é¡µ
@@ -277,19 +364,48 @@
        return list;
    }
    private void processSaveOrUpdate(List<ProductionPlan> list) {
    private int processSaveOrUpdate(List<ProductionPlan> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        int affected = 0;
        //  åŽ»é‡ formInstanceId
        Set<String> formIds = list.stream()
                .map(ProductionPlan::getFormInstanceId)
                .collect(Collectors.toSet());
        //  æŸ¥è¯¢æ•°æ®åº“已有数据
        List<ProductionPlan> existList = this.list(new LambdaQueryWrapper<ProductionPlan>().in(ProductionPlan::getFormInstanceId, formIds));
        //  Map (formInstanceId + materialCode)
        Map<String, ProductionPlan> existMap = new HashMap<>();
        for (ProductionPlan p : existList) {
            String key = p.getFormInstanceId() + "_" + p.getMaterialCode();
            existMap.put(key, p);
        }
        //  éåŽ†åŒæ­¥æ•°æ®
        for (ProductionPlan plan : list) {
            LambdaQueryWrapper<ProductionPlan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProductionPlan::getFormInstanceId, plan.getFormInstanceId())
                    .eq(ProductionPlan::getMaterialCode, plan.getMaterialCode());
            ProductionPlan existing = this.getOne(queryWrapper);
            if (existing != null) {
                plan.setId(existing.getId());
                this.updateById(plan);
            } else {
            String key = plan.getFormInstanceId() + "_" + plan.getMaterialCode();
            ProductionPlan exist = existMap.get(key);
            if (exist == null) {
                // æ–°å¢ž
                this.save(plan);
                affected++;
                log.info("新增数据 formInstanceId={}, materialCode={}", plan.getFormInstanceId(), plan.getMaterialCode());
            } else {
                // åˆ¤æ–­æ˜¯å¦éœ€è¦æ›´æ–°
                if (exist.getFormModifiedTime() == null || !exist.getFormModifiedTime().equals(plan.getFormModifiedTime())) {
                    plan.setId(exist.getId());
                    plan.setCreateTime(exist.getCreateTime());
                    this.updateById(plan);
                    affected++;
                    log.info("更新数据 formInstanceId={}, materialCode={}", plan.getFormInstanceId(), plan.getMaterialCode());
                }
            }
        }
        return affected;
    }
    private LocalDateTime parseUtcTime(String utcString) {
@@ -304,4 +420,9 @@
            return null;
        }
    }
    @Override
    public List<ProductionPlanSummaryDto> summaryByProductType(ProductionPlanSummaryDto query) {
        return baseMapper.selectSummaryByProductType(query);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -267,9 +267,9 @@
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
        ProductOrder productOrder = new ProductOrder();
        productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
//        productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
//        productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
//        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
        String string = productOrderServiceImpl.generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(string);
        productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
@@ -340,7 +340,7 @@
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getSaleLedgerProductId, productIds)
//                        .in(ProductOrder::getSaleLedgerProductId, productIds)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            List<Long> orderIds = productOrders.stream()
@@ -421,8 +421,8 @@
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getSaleLedgerProductId, productIds));
//            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
//                    .in(ProductOrder::getSaleLedgerProductId, productIds));
        }
    }
src/main/resources/mapper/productionPlan/ProductionPlanMapper.xml
@@ -44,4 +44,33 @@
        WHERE 1 = 1
    </select>
    <select id="selectSummaryByProductType" resultType="com.ruoyi.productionPlan.dto.ProductionPlanSummaryDto">
        SELECT
        material_code,
        product_name,
        product_spec,
        length,
        width,
        height,
        COALESCE(SUM(quantity),0) AS quantity,
        COALESCE(SUM(volume),0) AS volume
        FROM production_plan
        <where>
            <if test="materialCode != null and materialCode != ''">
                AND material_code LIKE CONCAT('%', #{materialCode}, '%')
            </if>
            <if test="productName != null and productName != ''">
                AND product_name LIKE CONCAT('%', #{productName}, '%')
            </if>
        </where>
        GROUP BY
        material_code,
        product_name,
        product_spec,
        length,
        width,
        height
    </select>
</mapper>