ソースを参照

aps-交期延期预警

sucheng 2 ヶ月 前
コミット
67dc5f0c3d

+ 13 - 1
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/dao/ApsProcessOperationProcessEquDao.java

@@ -151,7 +151,19 @@ public interface ApsProcessOperationProcessEquDao extends BaseMapper<ApsProcessO
 
     List<RollerTypeExcelLookVo> selectAllRollerTypeAndWorkShopAndDevice(@Param("tenantId") String tenantId);
 
-    List<ApsDeliveryOffsetDo> selectDeliveryOffestList();
+    List<ApsProcessOperationProcessEquDo> selectDeliveryOffestList(@Param("cardIdList") List<String> cardIdList);
+
+    List<ProductCardVo> selectProductionCards();
+
+    List<ProductCardAndLatestScheduleEndDateVo> selectAllLatestEndDateByCarIds(@Param("cardIdList") List<String> cardIdList);
+
+    List<ProductCardAndLatestScheduleEndDateVo> selectAllLatestEndDateByCarIds2(@Param("cardIdList") List<String> cardIdList);
+
+    List<ProductCardAndLatestScheduleEndDateVo> selectAllLatestEndDateByCarIds3(@Param("cardIdList") List<String> cardIdList);
+
+    List<String> selectAllNeedDelIds();
+
+    void myDeleteByIds(@Param("needDelIdList") List<String> needDelIdList);
 }
 
 

+ 150 - 5
cx-aps/cx-aps-common/src/main/java/com/rongwei/bscommon/sys/service/impl/ApsProcessOperationProcessEquServiceImpl.java

@@ -3017,11 +3017,156 @@ public class ApsProcessOperationProcessEquServiceImpl extends ServiceImpl<ApsPro
 
     @Override
     public R workDeliveryOffset(WorkDeliveryOffsetReq req) {
-        List<ApsDeliveryOffsetDo> list = this.baseMapper.selectDeliveryOffestList();
-        //新增现在的所有偏差
-        apsDeliveryOffsetService.saveOrUpdateBatch(list);
-        //需要
-        if (req.getNeedSendMessage()){
+        //查询所有没有交期偏差的生产卡片
+        List<ProductCardVo> list = this.baseMapper.selectProductionCards();
+        if (list.isEmpty()) {
+            log.info("没有查询到需要计算的卡片信息");
+            return R.ok();
+        }
+        //卡片ID集合
+        List<String> cardIdList = list.stream().map(ProductCardVo::getId).distinct().collect(Collectors.toList());
+        //查询卡片对应的 计划成品卷数>0的作业明细的最晚的排程完工时间
+        List<ProductCardAndLatestScheduleEndDateVo> cardIdAndScheduleEndDateList = this.baseMapper.selectAllLatestEndDateByCarIds(cardIdList);
+        //查询卡片对应的 计划成品卷数>0并且作业状态=待开工或加工中的作业明细的最晚的排程完工时间
+        List<ProductCardAndLatestScheduleEndDateVo> cardIdAndScheduleEndDateList2 = this.baseMapper.selectAllLatestEndDateByCarIds2(cardIdList);
+        //查询卡片对应的 计划成品卷数>0的作业明细最晚的实际完工时间
+        List<ProductCardAndLatestScheduleEndDateVo> cardIdAndScheduleEndDateList3 = this.baseMapper.selectAllLatestEndDateByCarIds3(cardIdList);
+
+        /**
+         * 计算每个料卷(卡片ID区分料卷)正在加工(作业状态=加工中)和准备开工(作业状态=待开工,并且待加工料卷批次号不为空)的作业明细,与原计划(预排程计划)完工时间偏差(整小时数,四舍五入),计算逻辑如下:
+         * 如果作业状态=加工中,则完工时间偏差=计划完工时间-排程完工时间
+         * 如果作业状态=待开工,则完工时间偏差=取其大(计划完工时间,当前时间+作业时长)-排程完工时间
+         */
+        List<ApsProcessOperationProcessEquDo> apsProcessOperationProcessEquDos = this.baseMapper.selectDeliveryOffestList(cardIdList);
+        //聚合<卡片ID,最大的时间偏差>
+        Map<String, Integer> maxOffsetTimeMap = apsProcessOperationProcessEquDos.stream()
+                .collect(
+                        Collectors.groupingBy(
+                                ApsProcessOperationProcessEquDo::getRoottaskid, Collectors.reducing(
+                                        0, // 默认值
+                                        ApsProcessOperationProcessEquDo::getTimeoffset,
+                                        Integer::max
+                                )));
+
+        //需要修改或新增的集合
+        List<ApsDeliveryOffsetDo> needUpdateOrInsertList = new LinkedList<>();
+        for (ProductCardVo productCardVo : list) {
+            ApsDeliveryOffsetDo apsDeliveryOffsetDo = new ApsDeliveryOffsetDo();
+            apsDeliveryOffsetDo.setId(productCardVo.getId());
+            apsDeliveryOffsetDo.setOrderid(productCardVo.getOrderId());
+            apsDeliveryOffsetDo.setBlankid(productCardVo.getBlankId());
+            apsDeliveryOffsetDo.setStatus(productCardVo.getStatus());
+
+            //计算每个料卷(卡片ID区分料卷)计划完工时间=计划成品卷数>0的作业明细的最晚的排程完工时间+订单的送货时长
+            //订单的送货时长(小时)
+            Integer deliverTime = productCardVo.getDeliverTime();
+            if (deliverTime == null) {
+                deliverTime = 0;
+            }
+            //计划成品卷数>0的作业明细的最晚的排程完工时间
+            ProductCardAndLatestScheduleEndDateVo productCardAndLatestScheduleEndDateVo = cardIdAndScheduleEndDateList.stream().filter(item -> item.getCardId().equals(productCardVo.getId())).findFirst().orElse(null);
+            if (productCardAndLatestScheduleEndDateVo != null) {
+                Date latestScheduleEndDate = productCardAndLatestScheduleEndDateVo.getLatestScheduleEndDate();
+                //料卷计划完工时间
+                DateTime planEndDate = DateUtil.offsetHour(latestScheduleEndDate, deliverTime);
+                apsDeliveryOffsetDo.setPlanenddate(planEndDate);
+            }
+
+            /**
+             * 计算每个料卷预计完工时间:
+             * 如果卡片的生产状态=待开工或加工中,
+             *  则=(计划成品卷数>0,并且作业状态=待开工或加工中的作业明细的最晚的排程完工时间)+订单的送货时长+料卷交货期偏差,
+             *      料卷交货期偏差=该料卷准备开工和正在加工的作业计划完工时间与原计划(预排程计划)完工时间偏差的最大偏差(大于零表示延期,小于零表示提前,零表示没有偏差)
+             * 如果卡片的生产状态=全部取消或部分取消或已完工,则=空(表示不需要显示)
+             */
+            if (Arrays.asList("待开工", "加工中").contains(productCardVo.getStatus())) {
+                ProductCardAndLatestScheduleEndDateVo latestScheduleEndDateVo = cardIdAndScheduleEndDateList2.stream().filter(item -> item.getCardId().equals(productCardVo.getId())).findFirst().orElse(null);
+                if (latestScheduleEndDateVo != null) {
+                    Date latestScheduleEndDate = latestScheduleEndDateVo.getLatestScheduleEndDate();
+                    Integer maxOffsetTime = maxOffsetTimeMap.getOrDefault(productCardVo.getId(), 0);
+                    int time = deliverTime + maxOffsetTime;
+                    DateTime guessEndDate = DateUtil.offsetHour(latestScheduleEndDate, time);
+                    apsDeliveryOffsetDo.setGuessenddate(guessEndDate);
+                }
+            } else {
+                apsDeliveryOffsetDo.setGuessenddate(null);
+            }
+
+            /**
+             * 计算每个料卷实际完工时间:
+             * 如果卡片的生产状态=部分取消或已完工,则=计划成品卷数>0的作业明细最晚的实际完工时间;
+             * 如果卡片的生产状态=待开工或加工中或全部取消,则为空(表示未完工,不需要显示)
+             */
+            if (Arrays.asList("部分取消", "已完工").contains(productCardVo.getStatus())) {
+                ProductCardAndLatestScheduleEndDateVo latestScheduleEndDateVo = cardIdAndScheduleEndDateList3.stream().filter(item -> item.getCardId().equals(productCardVo.getId())).findFirst().orElse(null);
+                if (latestScheduleEndDateVo != null) {
+                    DateTime latestScheduleEndDate = latestScheduleEndDateVo.getLatestScheduleEndDate();
+                    apsDeliveryOffsetDo.setActualenddate(latestScheduleEndDate);
+                }
+            } else {
+                apsDeliveryOffsetDo.setActualenddate(null);
+            }
+            /**
+             * 计算每个料卷交货期偏差(天):
+             * 如果卡片的生产状态=待开工或加工中,
+             * 如果料卷计划完工时间的日期在坯料计划承诺交货期起止范围内,则=空
+             * 如果料卷计划完工时间的日期<坯料计划承诺交货期起,则=料卷计划完工时间的日期-坯料计划承诺交货期起
+             * 如果料卷计划完工时间的日期>坯料计划承诺交货期止,则=料卷计划完工时间的日期-坯料计划承诺交货期止
+             * 如果卡片的生产状态=部分取消或已完工,
+             * 如果料卷实际完工时间的日期在坯料计划承诺交货期起止范围内,则=空
+             * 如果料卷实际完工时间的日期<坯料计划承诺交货期起,则=料卷实际完工时间的日期-坯料计划承诺交货期起
+             * 如果料卷实际完工时间的日期>坯料计划承诺交货期止,则=料卷实际完工时间的日期-坯料计划承诺交货期止
+             * 如果卡片的生产状态=全部取消,则=空(表示不显示偏差)
+             */
+            //坯料计划承诺交货期
+            String[] split = productCardVo.getPromiseDate().split("~");
+            DateTime promiseStartDate = DateUtil.parseDate(split[0] + " 00:00:00");
+            DateTime promiseEndDate = DateUtil.parseDate(split[1] + " 23:59:59");
+            if (Arrays.asList("待开工", "加工中","部分取消", "已完工").contains(productCardVo.getStatus())) {
+                DateTime endDate = null;
+                if (Arrays.asList("待开工", "加工中").contains(productCardVo.getStatus())){
+                    endDate = apsDeliveryOffsetDo.getPlanenddate();
+                }else {
+                    endDate = apsDeliveryOffsetDo.getActualenddate();
+                }
+                if (endDate != null) {
+                    //如果料卷计划完工时间的日期<坯料计划承诺交货期起,则=料卷计划完工时间的日期-坯料计划承诺交货期起
+                    if (endDate.before(promiseStartDate)) {
+                        int offsetDay = (int)DateUtil.between(promiseStartDate, endDate, DateUnit.DAY, false);
+                        apsDeliveryOffsetDo.setDeliveryoffset(offsetDay);
+                        // 如果料卷计划完工时间的日期>坯料计划承诺交货期止,则=料卷计划完工时间的日期-坯料计划承诺交货期止
+                    } else if (endDate.after(promiseEndDate)) {
+                        int offsetDay = (int)DateUtil.between(promiseEndDate, endDate, DateUnit.DAY, false);
+                        apsDeliveryOffsetDo.setDeliveryoffset(offsetDay);
+                    } else {
+                        apsDeliveryOffsetDo.setDeliveryoffset(null);
+                    }
+                }else {
+                    apsDeliveryOffsetDo.setDeliveryoffset(null);
+                }
+            } else {
+                apsDeliveryOffsetDo.setDeliveryoffset(null);
+            }
+            needUpdateOrInsertList.add(apsDeliveryOffsetDo);
+        }
+
+
+        if (!apsProcessOperationProcessEquDos.isEmpty()) {
+            apsProcessOperationProcessEquService.updateBatchById(apsProcessOperationProcessEquDos);
+        }
+        if (!needUpdateOrInsertList.isEmpty()) {
+            apsDeliveryOffsetService.saveOrUpdateBatch(needUpdateOrInsertList);
+        }
+        //反查需要删除的数据
+        List<String> needDelIdList = this.baseMapper.selectAllNeedDelIds();
+        if (!needDelIdList.isEmpty()){
+            this.baseMapper.myDeleteByIds(needDelIdList);
+        }
+        if (req.getNeedSendMessage()) {
+            List<ApsDeliveryOffsetDo> needSendMessageList = needUpdateOrInsertList.stream().filter(item -> Arrays.asList("待开工", "加工中").contains(item.getStatus()) && item.getDeliveryoffset() > 0).collect(Collectors.toList());
+            if (!needSendMessageList.isEmpty()){
+
+            }
 
         }
         return R.ok();

+ 209 - 8
cx-aps/cx-aps-common/src/main/resources/mybatis/ApsProcessOperationProcessEquDao.xml

@@ -45,7 +45,17 @@
         REPORTROLL,CHECKOUTROLL,UNFINISHROLL,
         WORKSTATUS,BACHMATERIALPROCESS,WAITREPORTID
     </sql>
-<!--    <update id="updateBachmaterialprocessByIds">-->
+    <delete id="myDeleteByIds">
+        DELETE
+        FROM
+            aps_delivery_offset
+        WHERE
+            ID IN
+        <foreach collection="needDelIdList" open="(" close=")" item="item" separator=",">
+            #{item}
+        </foreach>
+    </delete>
+    <!--    <update id="updateBachmaterialprocessByIds">-->
 <!--        update aps_process_operation_process_equ set BACHMATERIALPROCESS =-->
 <!--        CONCAT_WS(',',BACHMATERIALPROCESS,#{batchNum})-->
 <!--        <where>-->
@@ -727,12 +737,13 @@
         AND art.TENANTID = #{tenantId}
         ORDER BY aci.USEDEPTNAME,aci.CHECKITEMNAME,art.ROLLERTYPE
     </select>
-    <select id="selectDeliveryOffestList" resultType="com.rongwei.bsentity.domain.ApsDeliveryOffsetDo">
+    <select id="selectDeliveryOffestList" resultType="com.rongwei.bsentity.domain.ApsProcessOperationProcessEquDo">
         SELECT
-            apope.ROOTTASKID AS 'ID',
+            apope.ID,
+            apope.ROOTTASKID,
             IF(apope.WORKSTATUS = '加工中',
-               TIMESTAMPDIFF(HOUR,apope.SCHEDULEENDDATE,apope.PLANENDDATE),
-               TIMESTAMPDIFF(HOUR,apope.SCHEDULEENDDATE,GREATEST(apope.PLANENDDATE,DATE_ADD(now(),INTERVAL TIMESTAMPDIFF(MINUTE,apope.PLANSTARTDATE,apope.PLANENDDATE) MINUTE)))) AS 'DELIVERYOFFSET'
+               ROUND(TIMESTAMPDIFF(MINUTE,apope.SCHEDULEENDDATE,apope.PLANENDDATE)/60),
+               ROUND(TIMESTAMPDIFF(MINUTE,apope.SCHEDULEENDDATE,GREATEST(apope.PLANENDDATE,DATE_ADD(now(),INTERVAL TIMESTAMPDIFF(MINUTE,apope.PLANSTARTDATE,apope.PLANENDDATE) MINUTE)))/60)) AS 'TIMEOFFSET'
         FROM
             aps_process_operation_process_equ apope
                 LEFT JOIN aps_process_operation_process_equ preapope ON preapope.ID = apope.PREVIOUSPROCESSESIDS
@@ -741,8 +752,198 @@
             apope.DELETED = 0
           AND (
             apope.WORKSTATUS = '加工中'
-                OR (
-                apope.WORKSTATUS = '待开工'
-                    AND ( preapope.ID IS NULL OR preapope.WORKSTATUS = '已完工' )))
+                OR
+            (apope.WORKSTATUS = '待开工' AND apope.BACHMATERIALPROCESS != ''))
+          AND apope.ROOTTASKID IN
+            <foreach collection="cardIdList" open="(" close=")" item="item" separator=",">
+                #{item}
+            </foreach>
+    </select>
+    <select id="selectProductionCards" resultType="com.rongwei.bsentity.vo.ProductCardVo">
+        select a.* from (select
+        apope.ROOTTASKID as id,
+        max(abo.TENANTID) as tenantid,
+        max(abo.CUSTOMORDERNO) as customOrderNo,
+        max(abo.ORDERNO) as orderNo,
+        max(abo.CUSTOMNAME) as customName,
+        max(abo.BLANKNUMBER) as blankNumber, -- 坯料计划编号
+        max(abo.OUTPUTORDERPRODUCT) as outputOrderProduct, -- 输出订单产品
+        max(CONCAT(IFNULL(DATE(abo.PROMISEDATESTART),''),'~',IFNULL(DATE(abo.PROMISEDATEEND),''))) AS promiseDate, -- 承诺交货期
+        max(abo.PLANNEDPRODUCTIONWORKSHOP) as plannedProductionWorkshop, -- 计划排产车间
+        max(abo.ID) AS blankId, -- 坯料计划ID
+        max(abo.CRAFTROUTEID) as craftrouteId, -- 工艺路线ID
+        max(apro.AUDITDATE) as auditDate, -- 订单评审日期
+        -- 坯料批次号
+        max(
+        IF(apope.ID = apope.ROOTTASKID,
+        IF(apope.BLANKBATCHNUMBER is not null and apope.BLANKBATCHNUMBER!='',
+        apope.BLANKBATCHNUMBER,
+        IF(abo.PREPAREMATERIAL = '是',
+        SUBSTRING_INDEX( abo.PREPAREMATERIALBATCHNO, ',', 1 ),
+        apope.BACHMATERIALPROCESS
+        )
+        ),
+        null
+        )
+        ) AS blankBatchNumber,
+        max(IF(apope.ID = apope.ROOTTASKID, ifnull(arr.REPORTOUTMATERREQUEST,abo.INPUTREPORTDESCRIBE), null)) as blankDesc , -- 坯料描述
+        max(IF(apope.ID = apope.ROOTTASKID, arr.ID, null)) as reportId, -- 坯料报工记录ID
+        max(IF(apope.ID = apope.ROOTTASKID, arr.CHECKDATE, null)) as checkDate, -- 坯料检验日期
+        max(IF(apope.ID = apope.ROOTTASKID, arr.BLANKLEVEL, null)) as insepctionLevel, -- 坯料检验等级
+        -- 卡片状态
+        apope.status,
+        -- 最近修改时间
+        max(apope.MODIFYDATE) as cardModifyDate,
+        -- 最后报工记录的工序显示名
+        SUBSTRING_INDEX(group_concat(arr.REPORTPROCESSNAME order by arr.CREATEDATE desc), ',', 1) as processName,
+        '0' AS deleted,
+        apro.DELIVERYTIME AS deliverTime,
+        apro.ID AS orderId
+        FROM
+        (
+        SELECT
+        *,
+        -- 卡片状态
+        IF(sum(STARTINGROLL)=0,'待开工', -- 已开工卷数=0
+        if(sum(LEAVEWAITWORKROLL)>0,'加工中', -- 剩余待报工卷数>0
+        if(sum(CANCELROLL)=0,'已完工', -- 已取消卷数合计=0
+        if(sum(CANCELROLL)&lt;sum(PLANPROCESSRALL),'部分取消','全部取消')))) as STATUS -- 已取消卷数小于计划加工卷数
+            FROM
+            aps_process_operation_process_equ
+            WHERE
+            DELETED = 0
+        GROUP BY ROOTTASKID
+        ) apope
+        JOIN aps_blank_order abo ON apope.BLANKID = abo.ID
+        JOIN aps_production_order apro ON abo.PRODUCTIONORDERID = apro.ID
+        left join aps_report_records arr on arr.DELETED = '0' AND apope.id=arr.PROCESSEQUID
+        where
+        apope.DELETED = '0' AND abo.DELETED = '0' AND apro.DELETED = '0' and apope.ROOTTASKID != ''
+        and (apope.BLANKBATCHNUMBER!='' or abo.PREPAREMATERIAL = '是') -- 有坯料批次号
+        group by
+        apope.ROOTTASKID
+        ) a LEFT JOIN aps_delivery_offset ado ON a.ID = ado.ID AND ado.DELETED = 0
+        where ado.ID is null or (a.`STATUS` = ado.`STATUS` and a.`STATUS` = '已完工')
+    </select>
+    <select id="selectAllLatestEndDateByCarIds"
+            resultType="com.rongwei.bsentity.vo.ProductCardAndLatestScheduleEndDateVo">
+        SELECT
+            apope.ROOTTASKID as cardId,
+            MAX(apope.SCHEDULEENDDATE) AS latestScheduleEndDate
+        FROM
+            aps_process_operation_process_equ apope
+                JOIN aps_process_operation_out_mater apoom ON apope.PROCESSID = apoom.MAINID
+                AND apoom.DELETED = 0
+        WHERE
+            apope.DELETED = 0
+          AND apoom.PLANPRODROLLNUM > 0
+	      AND apope.ROOTTASKID IN
+        <foreach collection="cardIdList" open="(" close=")" item="item" separator=",">
+            #{item}
+        </foreach>
+        GROUP BY apope.ROOTTASKID
+    </select>
+    <select id="selectAllLatestEndDateByCarIds2"
+            resultType="com.rongwei.bsentity.vo.ProductCardAndLatestScheduleEndDateVo">
+        SELECT
+        apope.ROOTTASKID as cardId,
+        MAX(apope.SCHEDULEENDDATE) AS latestScheduleEndDate
+        FROM
+        aps_process_operation_process_equ apope
+        JOIN aps_process_operation_out_mater apoom ON apope.PROCESSID = apoom.MAINID
+        AND apoom.DELETED = 0
+        WHERE
+        apope.DELETED = 0
+        AND apoom.PLANPRODROLLNUM > 0
+        AND apope.WORKSTATUS IN ('待开工','加工中')
+        AND apope.ROOTTASKID IN
+        <foreach collection="cardIdList" open="(" close=")" item="item" separator=",">
+            #{item}
+        </foreach>
+        GROUP BY apope.ROOTTASKID
+    </select>
+    <select id="selectAllLatestEndDateByCarIds3"
+            resultType="com.rongwei.bsentity.vo.ProductCardAndLatestScheduleEndDateVo">
+        SELECT
+        apope.ROOTTASKID as cardId,
+        MAX(apope.ACTUALFINISHDATE) AS latestScheduleEndDate
+        FROM
+        aps_process_operation_process_equ apope
+        JOIN aps_process_operation_out_mater apoom ON apope.PROCESSID = apoom.MAINID
+        AND apoom.DELETED = 0
+        WHERE
+        apope.DELETED = 0
+        AND apoom.PLANPRODROLLNUM > 0
+        AND apope.ROOTTASKID IN
+        <foreach collection="cardIdList" open="(" close=")" item="item" separator=",">
+            #{item}
+        </foreach>
+        GROUP BY apope.ROOTTASKID
+    </select>
+    <select id="selectAllNeedDelIds" resultType="java.lang.String">
+        select ado.ID from (select
+        apope.ROOTTASKID as id,
+        max(abo.TENANTID) as tenantid,
+        max(abo.CUSTOMORDERNO) as customOrderNo,
+        max(abo.ORDERNO) as orderNo,
+        max(abo.CUSTOMNAME) as customName,
+        max(abo.BLANKNUMBER) as blankNumber, -- 坯料计划编号
+        max(abo.OUTPUTORDERPRODUCT) as outputOrderProduct, -- 输出订单产品
+        max(CONCAT(IFNULL(DATE(abo.PROMISEDATESTART),''),'~',IFNULL(DATE(abo.PROMISEDATEEND),''))) AS promiseDate, -- 承诺交货期
+        max(abo.PLANNEDPRODUCTIONWORKSHOP) as plannedProductionWorkshop, -- 计划排产车间
+        max(abo.ID) AS blankId, -- 坯料计划ID
+        max(abo.CRAFTROUTEID) as craftrouteId, -- 工艺路线ID
+        max(apro.AUDITDATE) as auditDate, -- 订单评审日期
+        -- 坯料批次号
+        max(
+        IF(apope.ID = apope.ROOTTASKID,
+        IF(apope.BLANKBATCHNUMBER is not null and apope.BLANKBATCHNUMBER!='',
+        apope.BLANKBATCHNUMBER,
+        IF(abo.PREPAREMATERIAL = '是',
+        SUBSTRING_INDEX( abo.PREPAREMATERIALBATCHNO, ',', 1 ),
+        apope.BACHMATERIALPROCESS
+        )
+        ),
+        null
+        )
+        ) AS blankBatchNumber,
+        max(IF(apope.ID = apope.ROOTTASKID, ifnull(arr.REPORTOUTMATERREQUEST,abo.INPUTREPORTDESCRIBE), null)) as blankDesc , -- 坯料描述
+        max(IF(apope.ID = apope.ROOTTASKID, arr.ID, null)) as reportId, -- 坯料报工记录ID
+        max(IF(apope.ID = apope.ROOTTASKID, arr.CHECKDATE, null)) as checkDate, -- 坯料检验日期
+        max(IF(apope.ID = apope.ROOTTASKID, arr.BLANKLEVEL, null)) as insepctionLevel, -- 坯料检验等级
+        -- 卡片状态
+        apope.status,
+        -- 最近修改时间
+        max(apope.MODIFYDATE) as cardModifyDate,
+        -- 最后报工记录的工序显示名
+        SUBSTRING_INDEX(group_concat(arr.REPORTPROCESSNAME order by arr.CREATEDATE desc), ',', 1) as processName,
+        '0' AS deleted,
+        apro.DELIVERYTIME AS deliverTime,
+        apro.ID AS orderId
+        FROM
+        (
+        SELECT
+        *,
+        -- 卡片状态
+        IF(sum(STARTINGROLL)=0,'待开工', -- 已开工卷数=0
+        if(sum(LEAVEWAITWORKROLL)>0,'加工中', -- 剩余待报工卷数>0
+        if(sum(CANCELROLL)=0,'已完工', -- 已取消卷数合计=0
+        if(sum(CANCELROLL)&lt;sum(PLANPROCESSRALL),'部分取消','全部取消')))) as STATUS -- 已取消卷数小于计划加工卷数
+        FROM
+        aps_process_operation_process_equ
+        WHERE
+        DELETED = 0
+        GROUP BY ROOTTASKID
+        ) apope
+        JOIN aps_blank_order abo ON apope.BLANKID = abo.ID
+        JOIN aps_production_order apro ON abo.PRODUCTIONORDERID = apro.ID
+        left join aps_report_records arr on arr.DELETED = '0' AND apope.id=arr.PROCESSEQUID
+        where
+        apope.DELETED = '0' AND abo.DELETED = '0' AND apro.DELETED = '0' and apope.ROOTTASKID != ''
+        and (apope.BLANKBATCHNUMBER!='' or abo.PREPAREMATERIAL = '是') -- 有坯料批次号
+        group by
+        apope.ROOTTASKID
+        ) a RIGHT JOIN aps_delivery_offset ado ON a.ID = ado.ID AND ado.DELETED = 0
+        where a.ID is null
     </select>
 </mapper>

+ 42 - 1
cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/domain/ApsDeliveryOffsetDo.java

@@ -1,5 +1,7 @@
 package com.rongwei.bsentity.domain;
 
+import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -7,6 +9,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import com.rongwei.rwcommon.base.BaseDo;
 import lombok.Data;
 
+import java.util.Date;
+
 /**
  * 生产订单-坯料计划-工序作业加工设备-作业明细-料卷交货期偏差
  * @TableName aps_delivery_offset
@@ -35,9 +39,46 @@ public class ApsDeliveryOffsetDo extends BaseDo {
     /**
      * 料卷交货期偏差
      */
-    @TableField(value = "DELIVERYOFFSET")
+    @TableField(value = "DELIVERYOFFSET",updateStrategy = FieldStrategy.IGNORED)
     private Integer deliveryoffset;
 
+    /**
+     * 料卷计划完工时间
+     */
+    @TableField(value = "PLANENDDATE")
+    private DateTime planenddate;
+
+    /**
+     * 料卷预计完工时间
+     */
+    @TableField(value = "GUESSENDDATE",updateStrategy = FieldStrategy.IGNORED)
+    private DateTime guessenddate;
+
+    /**
+     * 料卷实际完工时间
+     */
+    @TableField(value = "ACTUALENDDATE",updateStrategy = FieldStrategy.IGNORED)
+    private DateTime actualenddate;
+
+    /**
+     * 卡片状态
+     */
+    @TableField(value = "STATUS")
+    private String status;
+
+    /**
+     * 订单ID
+     */
+    @TableField(value = "ORDERID")
+    private String orderid;
+
+    /**
+     * 坯料计划ID
+     */
+    @TableField(value = "BLANKID")
+    private String blankid;
+
+
     @TableField(exist = false)
     private static final long serialVersionUID = 1L;
 }

+ 5 - 0
cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/domain/ApsProcessOperationProcessEquDo.java

@@ -258,4 +258,9 @@ public class ApsProcessOperationProcessEquDo extends BaseDo {
      */
     @TableField("SCHEDULEENDDATE")
     private Date scheduleenddate;
+    /**
+     * 时间偏差
+     */
+    @TableField("TIMEOFFSET")
+    private Integer timeoffset;
 }

+ 14 - 0
cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/vo/ProductCardAndLatestScheduleEndDateVo.java

@@ -0,0 +1,14 @@
+package com.rongwei.bsentity.vo;
+
+import cn.hutool.core.date.DateTime;
+import lombok.Data;
+
+/**
+ * @author :sc
+ * @since :2025/5/22
+ */
+@Data
+public class ProductCardAndLatestScheduleEndDateVo {
+    private String cardId;
+    private DateTime latestScheduleEndDate;
+}

+ 49 - 0
cx-aps/cx-aps-entity/src/main/java/com/rongwei/bsentity/vo/ProductCardVo.java

@@ -0,0 +1,49 @@
+package com.rongwei.bsentity.vo;
+
+import com.rongwei.rwcommon.base.BaseDo;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author :sc
+ * @since :2025/5/22
+ */
+@Data
+public class ProductCardVo extends BaseDo {
+    private String id;
+    private String customOrderNo;
+    private String orderNo;
+    private String customName;
+    private String blankNumber;
+    private String outputOrderProduct;
+    //承诺交货期
+    private String promiseDate;
+    //计划排产车间
+    private String plannedProductionWorkshop;
+    private String blankId;
+    //工艺路线ID
+    private String craftrouteId;
+    //订单评审日期
+    private Date auditDate;
+    //坯料批次号
+    private String blankBatchNumber;
+    //坯料描述
+    private String blankDesc;
+    //报工记录ID
+    private String reportId;
+    //坯料检验日期
+    private Date checkDate;
+    //坯料检验等级
+    private String insepctionLevel;
+    //卡片状态
+    private String status;
+    //最近修改时间
+    private Date cardModifyDate;
+    //工序显示名
+    private String processName;
+    //送货时长
+    private Integer deliverTime;
+    //订单ID
+    private String orderId;
+}