Bladeren bron

Merge branch 'redesign‌-260706' of git.huaml.com:zhh/huahuibao into redesign‌-260706

shizhongqi 7 uur geleden
bovenliggende
commit
6b1057ea55

+ 50 - 3
app-ghs/controllers/StatCgGhsController.php

@@ -3,6 +3,7 @@
 namespace ghs\controllers;
 
 use biz\stat\classes\StatCgGhsClass;
+use bizGhs\cg\classes\CgPurchaseNextDayClass;
 use bizGhs\cg\classes\CgRefundClass;
 use bizGhs\ghs\classes\GhsClass;
 use bizGhs\order\classes\PurchaseOrderClass;
@@ -15,7 +16,10 @@ use common\components\util;
 class StatCgGhsController extends BaseController
 {
 
-    //采购列表 ssh 20211017
+    /**
+     * 供货业绩:入库日累加 actPrice(当天售后已减实付);
+     * 隔天售后按通过日扣金额(可为负,笔数不减),对齐销售客户业绩口径。
+     */
     public function actionProfile()
     {
         $get = Yii::$app->request->get();
@@ -74,7 +78,12 @@ class StatCgGhsController extends BaseController
                         $classId = $orderItem['classId'] ?? 0;
                         if (getenv('YII_ENV') == 'production') {
                             if ($mainId == 23390) {
-                                $remainNum = bcsub($num, $refundNum);
+                                // 运费花材:入库日净量不含隔天退货
+                                $remainNum = CgPurchaseNextDayClass::payDayRemainNum(
+                                    $num,
+                                    $refundNum,
+                                    $orderItem['nextRefundNum'] ?? 0
+                                );
                                 $amount = bcmul($remainNum, $unitPrice, 2);
                                 if ($classId == 73120) {
                                     $freight = bcadd($freight, $amount, 2);
@@ -84,12 +93,16 @@ class StatCgGhsController extends BaseController
                     }
                 }
 
-                //增加项
+                //增加项:仅退款(含当天);隔天仅退款金额在下方通过日一并扣 actPrice
                 if ($tkPrice > 0) {
                     $refundList = CgRefundClass::getAllByCondition(['relateOrderSn' => $orderSn], null, '*', null, true);
                     if (!empty($refundList)) {
                         foreach ($refundList as $refundInfo) {
                             if (isset($refundInfo->refundType) && $refundInfo->refundType == 2) {
+                                // 隔天仅退款记在通过日,入库日不重复计入 onlyTk
+                                if (intval($refundInfo->sameDay ?? 1) === CgPurchaseNextDayClass::SAME_DAY_NO) {
+                                    continue;
+                                }
                                 $refundPrice = $refundInfo->refundPrice ?? 0;
                                 $totalOnlyTkPrice = bcadd($totalOnlyTkPrice, $refundPrice, 2);
                             }
@@ -129,6 +142,38 @@ class StatCgGhsController extends BaseController
                     ];
                 }
             }
+        }
+
+        // 隔天售后:按通过日扣供货商金额;无当日入库也建负行(笔数不减)
+        $nextMap = CgPurchaseNextDayClass::sumAmountGroupByGhs($mainId, $currentStartTime, $currentEndTime);
+        foreach ($nextMap as $ghsId => $amt) {
+            if (bccomp((string)$amt, '0', 2) <= 0) {
+                continue;
+            }
+            if (!isset($list[$ghsId])) {
+                $name = isset($ghsList[$ghsId]) && !empty($ghsList[$ghsId]['name']) ? $ghsList[$ghsId]['name'] : '未命名';
+                $mobile = isset($ghsList[$ghsId]) && !empty($ghsList[$ghsId]['mobile']) ? $ghsList[$ghsId]['mobile'] : '0';
+                $list[$ghsId] = [
+                    'id' => $ghsId,
+                    'name' => $name,
+                    'mobile' => $mobile,
+                    'orderPrice' => 0,
+                    'actPrice' => '0.00',
+                    'num' => 0,
+                    'carton' => 0,
+                    'pack' => 0,
+                    'freight' => 0,
+                    'tkPrice' => 0,
+                ];
+            }
+            $list[$ghsId]['actPrice'] = bcsub((string)$list[$ghsId]['actPrice'], (string)$amt, 2);
+            $list[$ghsId]['tkPrice'] = bcadd((string)($list[$ghsId]['tkPrice'] ?? 0), (string)$amt, 2);
+            $totalActPrice = bcsub((string)$totalActPrice, (string)$amt, 2);
+            $totalTkPrice = bcadd((string)$totalTkPrice, (string)$amt, 2);
+        }
+
+        // 有入库单时补齐本主账号下全部供货商行(与旧逻辑一致)
+        if (!empty($orderList)) {
             foreach ($ghsList as $key => $ghs) {
                 $ghsId = $ghs['id'] ?? 0;
                 if (isset($list[$ghsId]) == false) {
@@ -146,6 +191,8 @@ class StatCgGhsController extends BaseController
                     ];
                 }
             }
+        }
+        if (!empty($list)) {
             $list = array_values($list);
         }
         if ($export == 1) {

+ 228 - 2
biz-ghs/cg/classes/CgPurchaseNextDayClass.php

@@ -1,14 +1,17 @@
 <?php
 /**
  * 上游采购隔天售后业务类(biz-ghs/cg/classes)
- * 用途:按入库日/结清状态判定当天 vs 隔天;写支付快照;隔天累加 nextDayTkPrice 并买方加余额。
- * 调用方:CgRefundService、CgRefundController;与销售 NextDayRefundClass 语义对齐,时间基准用 entryTime。
+ * 用途:按入库日/结清状态判定当天 vs 隔天;写支付快照;隔天累加 nextDayTkPrice 并买方加余额;
+ * 统计辅助:入库日净量、通过日按供货商/采购人/花材扣减。
+ * 调用方:CgRefundService、CgRefundController、StatCgClass、StatCgGhsController。
  */
 namespace bizGhs\cg\classes;
 
 use bizGhs\order\classes\PurchaseOrderClass;
+use bizGhs\order\classes\PurchaseOrderItemClass;
 use common\components\dict;
 use common\components\util;
+use Yii;
 
 class CgPurchaseNextDayClass
 {
@@ -166,4 +169,227 @@ class CgPurchaseNextDayClass
         $refund->hasReturn = self::FLAG_YES;
         $refund->save(false, ['hasReturn']);
     }
+
+    /**
+     * 入库日净采购量:当天已退 = refundNum - nextRefundNum,净量 = itemNum - 当天已退。
+     * 隔天退货记在 nextRefundNum,不在入库日扣掉(通过日再扣)。
+     *
+     * @param mixed $itemNum 采购数量
+     * @param mixed $refundNum 总已退
+     * @param mixed $nextRefundNum 隔天已退
+     * @return string
+     */
+    public static function payDayRemainNum($itemNum, $refundNum, $nextRefundNum = 0)
+    {
+        $sameDayRefund = bcsub((string)$refundNum, (string)($nextRefundNum ?? 0), 2);
+        if (bccomp($sameDayRefund, '0', 2) < 0) {
+            $sameDayRefund = '0';
+        }
+        return bcsub((string)$itemNum, $sameDayRefund, 2);
+    }
+
+    /**
+     * 通过日有效时间:passTime 为空时回退 addTime(与销售统计一致)
+     */
+    private static function passTimeSqlExpr($alias = 'r')
+    {
+        return "IFNULL(NULLIF({$alias}.passTime,'0000-00-00 00:00:00'), {$alias}.addTime)";
+    }
+
+    /**
+     * 按供货商汇总隔天售后金额(供货业绩 cgStat 通过日扣减)
+     * @return array ghsId => amount
+     */
+    public static function sumAmountGroupByGhs($mainId, $startTime, $endTime)
+    {
+        $passExpr = self::passTimeSqlExpr('r');
+        $sql = "SELECT r.ghsId, COALESCE(SUM(r.refundPrice),0) AS total
+            FROM xhGhsCgRefund r
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND {$passExpr} BETWEEN :start AND :end
+            GROUP BY r.ghsId";
+        $rows = Yii::$app->db->createCommand($sql, [
+            ':mainId' => intval($mainId),
+            ':status' => 1,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryAll();
+        $map = [];
+        foreach ($rows as $row) {
+            $map[intval($row['ghsId'] ?? 0)] = bcadd($row['total'] ?? '0', '0', 2);
+        }
+        return $map;
+    }
+
+    /**
+     * 按原采购单采购人汇总隔天售后金额(采购人业绩 cgYj 通过日扣减,笔数不减)
+     * @return array cgStaffId => [amount, cgStaffName]
+     */
+    public static function sumAmountGroupByCgStaff($mainId, $startTime, $endTime)
+    {
+        $passExpr = self::passTimeSqlExpr('r');
+        $sql = "SELECT IFNULL(o.cgStaffId,0) AS cgStaffId,
+                MAX(IFNULL(o.cgStaffName,'')) AS cgStaffName,
+                COALESCE(SUM(r.refundPrice),0) AS total
+            FROM xhGhsCgRefund r
+            INNER JOIN xhGhsCgOrder o ON o.orderSn = r.relateOrderSn
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND {$passExpr} BETWEEN :start AND :end
+            GROUP BY o.cgStaffId";
+        $rows = Yii::$app->db->createCommand($sql, [
+            ':mainId' => intval($mainId),
+            ':status' => 1,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryAll();
+        $map = [];
+        foreach ($rows as $row) {
+            $sid = intval($row['cgStaffId'] ?? 0);
+            $map[$sid] = [
+                'amount' => bcadd($row['total'] ?? '0', '0', 2),
+                'cgStaffName' => (string)($row['cgStaffName'] ?? ''),
+            ];
+        }
+        return $map;
+    }
+
+    /**
+     * 按花材汇总隔天退货数量与金额(退货退款明细;itemId=productId)
+     * @return array productId => [num, amount]
+     */
+    public static function sumItemByProduct($mainId, $startTime, $endTime)
+    {
+        $passExpr = self::passTimeSqlExpr('r');
+        $sql = "SELECT i.itemId AS productId,
+                COALESCE(SUM(i.num),0) AS num,
+                COALESCE(SUM(i.price),0) AS amount
+            FROM xhGhsCgRefundItem i
+            INNER JOIN xhGhsCgRefund r ON r.refundSn = i.refundSn
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND r.refundType=:rtype
+              AND {$passExpr} BETWEEN :start AND :end
+            GROUP BY i.itemId";
+        $rows = Yii::$app->db->createCommand($sql, [
+            ':mainId' => intval($mainId),
+            ':status' => 1,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':rtype' => CgRefundClass::REFUND_TYPE_MONEY_GOOD,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryAll();
+        $map = [];
+        foreach ($rows as $row) {
+            $pid = intval($row['productId'] ?? 0);
+            if ($pid <= 0) {
+                continue;
+            }
+            $map[$pid] = [
+                'num' => bcadd($row['num'] ?? '0', '0', 2),
+                'amount' => bcadd($row['amount'] ?? '0', '0', 2),
+            ];
+        }
+        return $map;
+    }
+
+    /**
+     * 隔天「仅退款」按原采购明细金额占比分摊到花材(通过日只扣金额不扣数量)
+     * @return array productId => [num=>0, amount=>...]
+     */
+    public static function sumMoneyOnlyAmountByProduct($mainId, $startTime, $endTime)
+    {
+        $passExpr = self::passTimeSqlExpr('r');
+        $sql = "SELECT r.id, r.refundPrice, r.relateOrderSn
+            FROM xhGhsCgRefund r
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND r.refundType=:rtype
+              AND IFNULL(NULLIF(r.relateOrderSn,''), '') <> ''
+              AND {$passExpr} BETWEEN :start AND :end";
+        $rows = Yii::$app->db->createCommand($sql, [
+            ':mainId' => intval($mainId),
+            ':status' => 1,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':rtype' => CgRefundClass::REFUND_TYPE_MONEY,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryAll();
+        if (empty($rows)) {
+            return [];
+        }
+        $map = [];
+        foreach ($rows as $row) {
+            $refundPrice = bcadd((string)($row['refundPrice'] ?? '0'), '0', 2);
+            if (bccomp($refundPrice, '0', 2) <= 0) {
+                continue;
+            }
+            $relateSn = $row['relateOrderSn'] ?? '';
+            $items = PurchaseOrderItemClass::getAllByCondition(
+                ['orderSn' => $relateSn],
+                null,
+                'productId,itemNum,bigPrice',
+                null,
+                true
+            );
+            if (empty($items)) {
+                continue;
+            }
+            $weights = [];
+            $weightSum = '0.00';
+            foreach ($items as $item) {
+                $pid = intval($item->productId ?? 0);
+                if ($pid <= 0) {
+                    continue;
+                }
+                $line = bcmul((string)($item->itemNum ?? '0'), (string)($item->bigPrice ?? '0'), 2);
+                if (bccomp($line, '0', 2) <= 0) {
+                    continue;
+                }
+                $weights[$pid] = bcadd($weights[$pid] ?? '0', $line, 2);
+                $weightSum = bcadd($weightSum, $line, 2);
+            }
+            if (bccomp($weightSum, '0', 2) <= 0) {
+                continue;
+            }
+            $allocated = '0.00';
+            $pids = array_keys($weights);
+            $last = count($pids) - 1;
+            foreach ($pids as $idx => $pid) {
+                if ($idx === $last) {
+                    $part = bcsub($refundPrice, $allocated, 2);
+                } else {
+                    $part = bcdiv(bcmul($refundPrice, $weights[$pid], 4), $weightSum, 2);
+                    $allocated = bcadd($allocated, $part, 2);
+                }
+                if (!isset($map[$pid])) {
+                    $map[$pid] = ['num' => '0.00', 'amount' => '0.00'];
+                }
+                $map[$pid]['amount'] = bcadd($map[$pid]['amount'], $part, 2);
+            }
+        }
+        return $map;
+    }
+
+    /**
+     * 隔天「仅退款」按通过日汇总金额(收支分类「采购仅退款」)
+     * @return string
+     */
+    public static function sumMoneyOnlyAmountByMainAndTime($mainId, $startTime, $endTime)
+    {
+        $passExpr = self::passTimeSqlExpr('r');
+        $sql = "SELECT COALESCE(SUM(r.refundPrice),0) AS total
+            FROM xhGhsCgRefund r
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND r.refundType=:rtype
+              AND {$passExpr} BETWEEN :start AND :end";
+        $row = Yii::$app->db->createCommand($sql, [
+            ':mainId' => intval($mainId),
+            ':status' => 1,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':rtype' => CgRefundClass::REFUND_TYPE_MONEY,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryOne();
+        return bcadd($row['total'] ?? '0', '0', 2);
+    }
 }

+ 84 - 4
biz-ghs/stat/classes/StatCgClass.php

@@ -1,7 +1,11 @@
 <?php
-
+/**
+ * 采购统计:花材排行 / 采购人业绩。
+ * 口径对齐销售隔天售后:入库日用 nextRefundNum 算净量;通过日再扣隔天金额/数量(可为负,笔数不减)。
+ */
 namespace bizGhs\stat\classes;
 
+use bizGhs\cg\classes\CgPurchaseNextDayClass;
 use bizGhs\order\classes\PurchaseOrderClass;
 use bizGhs\order\classes\PurchaseOrderItemClass;
 use bizGhs\product\classes\ProductClass;
@@ -14,6 +18,11 @@ use bizGhs\base\classes\BaseClass;
 class StatCgClass extends BaseClass
 {
 
+    /**
+     * 采购花材排行(兼返回采购人按明细汇总,供兼容旧调用)
+     * @param int $mainId
+     * @return array{itemList:array,staffCg:array}
+     */
     public static function statCg($mainId)
     {
         $get = Yii::$app->request->get();
@@ -57,7 +66,12 @@ class StatCgClass extends BaseClass
                         $productId = $val->productId ?? 0;
                         $num = $val->itemNum ?? 0;
                         $refundNum = $val->refundNum ?? 0;
-                        $remainNum = bcsub($num, $refundNum);
+                        // 入库日净量:隔天已退记在 nextRefundNum,不在入库日扣
+                        $remainNum = CgPurchaseNextDayClass::payDayRemainNum(
+                            $num,
+                            $refundNum,
+                            $val->nextRefundNum ?? 0
+                        );
                         $unitPrice = $val->bigPrice ?? 0;
                         $name = $productInfo[$productId]['name'] ?? '';
                         $py = $productInfo[$productId]['py'] ?? '';
@@ -90,6 +104,10 @@ class StatCgClass extends BaseClass
                 }
             }
         }
+
+        // 隔天售后:按通过日扣花材数量/金额;无当日入库也建负行
+        self::applyNextDayAdjustToCgItemRows($arr, $productInfo, $mainId, $currentStartTime, $currentEndTime);
+
         if (!empty($arr)) {
             $arr = array_values($arr);
             $arr = arrayUtil::arraySort($arr, $rank);
@@ -106,6 +124,46 @@ class StatCgClass extends BaseClass
         return ['itemList' => $arr, 'staffCg' => $cgData];
     }
 
+    /**
+     * 通过日扣减采购花材:退货退款扣数量+金额;仅退款只扣金额(按原单占比分摊)
+     *
+     * @param array $arr productId => 行
+     * @param array $productInfo 花材字典
+     * @param int $mainId
+     * @param string $startTime
+     * @param string $endTime
+     */
+    private static function applyNextDayAdjustToCgItemRows(
+        &$arr,
+        $productInfo,
+        $mainId,
+        $startTime,
+        $endTime
+    ) {
+        $applyDelta = function ($pidMap, $sign) use (&$arr, $productInfo) {
+            foreach ($pidMap as $pid => $row) {
+                $deltaNum = bcmul((string)($row['num'] ?? '0'), (string)$sign, 2);
+                $deltaAmt = bcmul((string)($row['amount'] ?? '0'), (string)$sign, 2);
+                if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
+                    continue;
+                }
+                if (!isset($arr[$pid])) {
+                    $arr[$pid] = [
+                        'num' => '0.00',
+                        'amount' => '0.00',
+                        'py' => $productInfo[$pid]['py'] ?? '',
+                        'name' => $productInfo[$pid]['name'] ?? '已删除',
+                    ];
+                }
+                $arr[$pid]['num'] = bcadd((string)($arr[$pid]['num'] ?? 0), $deltaNum, 2);
+                $arr[$pid]['amount'] = bcadd((string)($arr[$pid]['amount'] ?? 0), $deltaAmt, 2);
+            }
+        };
+
+        $applyDelta(CgPurchaseNextDayClass::sumItemByProduct($mainId, $startTime, $endTime), -1);
+        $applyDelta(CgPurchaseNextDayClass::sumMoneyOnlyAmountByProduct($mainId, $startTime, $endTime), -1);
+    }
+
     public static function exportCgItem($list, $mainId)
     {
         $phpExcelFile = Yii::getAlias("@vendor/phpoffice/phpexcel/");
@@ -177,7 +235,11 @@ class StatCgClass extends BaseClass
         util::success(['file' => $fileUrl, 'shortFile' => $file]);
     }
 
-    //采购人业绩 ssh 20240412
+    /**
+     * 采购人业绩:入库日按 actPrice(当天售后已减实付);隔天售后按通过日扣金额,笔数不减。
+     * @param int $mainId
+     * @return array{staffCg:array}
+     */
     public static function statCgYj($mainId)
     {
         $get = Yii::$app->request->get();
@@ -219,10 +281,28 @@ class StatCgClass extends BaseClass
             }
         }
 
+        // 隔天售后:按原单采购人扣金额;无当日入库也建负行(笔数不减)
+        $nextMap = CgPurchaseNextDayClass::sumAmountGroupByCgStaff($mainId, $currentStartTime, $currentEndTime);
+        foreach ($nextMap as $sid => $row) {
+            $amt = $row['amount'] ?? '0';
+            if (bccomp((string)$amt, '0', 2) <= 0) {
+                continue;
+            }
+            if (!isset($cgData[$sid])) {
+                $cgData[$sid] = [
+                    'cgStaffId' => $sid,
+                    'cgStaffName' => $row['cgStaffName'] ?? '',
+                    'amount' => '0.00',
+                    'num' => 0,
+                ];
+            }
+            $cgData[$sid]['amount'] = bcsub((string)$cgData[$sid]['amount'], (string)$amt, 2);
+        }
+
         if (!empty($cgData)) {
             $cgData = array_values($cgData);
         }
         return ['staffCg' => $cgData];
     }
 
-}
+}

+ 56 - 1
biz-ghs/stat/classes/StatSaleClass.php

@@ -5,6 +5,7 @@ namespace bizGhs\stat\classes;
 use biz\stat\classes\StatStockInClass;
 use biz\stat\classes\StatStockOutClass;
 use bizGhs\cg\classes\CgRefundClass;
+use bizGhs\cg\classes\CgPurchaseNextDayClass;
 use bizGhs\custom\classes\CustomClass;
 use bizGhs\custom\classes\DistClass;
 use bizGhs\expend\classes\ExpendClass;
@@ -1029,7 +1030,12 @@ class StatSaleClass extends BaseClass
                         $productId = $cgData->productId ?? 0;
                         $name = $cgData->name ?? '';
                         $refundNum = $cgData->refundNum ?? 0;
-                        $remainNum = bcsub($itemNum, $refundNum);
+                        // 入库日净量:隔天退货记 nextRefundNum,通过日再扣成本
+                        $remainNum = CgPurchaseNextDayClass::payDayRemainNum(
+                            $itemNum,
+                            $refundNum,
+                            $cgData->nextRefundNum ?? 0
+                        );
                         $bigPrice = $cgData->bigPrice ?? 0;
                         $amount = bcmul($remainNum, $bigPrice, 2);
                         $classId = $cgData->classId;
@@ -1072,6 +1078,11 @@ class StatSaleClass extends BaseClass
                         if (!empty($cgRefundOrderList)) {
                             foreach ($cgRefundOrderList as $cgRefundOrder) {
                                 if ($cgRefundOrder->refundType == 2) {
+                                    // 隔天仅退款记在通过日,避免与下方汇总重复
+                                    if (intval($cgRefundOrder->sameDay ?? CgPurchaseNextDayClass::SAME_DAY_YES)
+                                        === CgPurchaseNextDayClass::SAME_DAY_NO) {
+                                        continue;
+                                    }
                                     $onlyRefundCg = bcadd($cgRefundOrder->refundPrice, $onlyRefundCg, 2);
                                 }
                             }
@@ -1081,6 +1092,50 @@ class StatSaleClass extends BaseClass
             }
         }
 
+        // 采购隔天售后:入库日已用 nextRefundNum;通过日再扣分类成本;仅退款进「采购仅退款」
+        $productClassMapForCg = ProductClass::getAllByCondition(['mainId' => $mainId], null, 'id,classId,name', 'id');
+        $applyCgClassDelta = function ($pidMap, $sign) use (&$arr, &$classList, $productClassMapForCg, &$tbCgIncome) {
+            foreach ($pidMap as $pid => $row) {
+                $classId = $productClassMapForCg[$pid]['classId'] ?? 0;
+                $deltaNum = bcmul((string)($row['num'] ?? '0'), (string)$sign, 2);
+                $deltaAmt = bcmul((string)($row['amount'] ?? '0'), (string)$sign, 2);
+                if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
+                    continue;
+                }
+                if (!isset($arr[$classId])) {
+                    $arr[$classId] = [
+                        'className' => $classList[$classId]['name'] ?? '已删除',
+                        'classId' => $classId,
+                        'expend' => '0.00',
+                        'income' => 0,
+                        'saleNum' => 0,
+                        'cgNum' => '0.00',
+                    ];
+                }
+                $arr[$classId]['expend'] = bcadd((string)($arr[$classId]['expend'] ?? 0), $deltaAmt, 2);
+                $arr[$classId]['cgNum'] = bcadd((string)($arr[$classId]['cgNum'] ?? 0), $deltaNum, 2);
+                // 采购单项明细同步扣减(无当日入库也建负行)
+                if (!isset($tbCgIncome[$pid])) {
+                    $tbCgIncome[$pid] = [
+                        'num' => '0.00',
+                        'name' => $productClassMapForCg[$pid]['name'] ?? '已删除',
+                        'price' => '0.00',
+                    ];
+                }
+                $tbCgIncome[$pid]['num'] = bcadd((string)($tbCgIncome[$pid]['num'] ?? 0), $deltaNum, 2);
+                $tbCgIncome[$pid]['price'] = bcadd((string)($tbCgIncome[$pid]['price'] ?? 0), $deltaAmt, 2);
+            }
+        };
+        $applyCgClassDelta(
+            CgPurchaseNextDayClass::sumItemByProduct($mainId, $currentStartTime, $currentEndTime),
+            -1
+        );
+        $onlyRefundCg = bcadd(
+            (string)$onlyRefundCg,
+            CgPurchaseNextDayClass::sumMoneyOnlyAmountByMainAndTime($mainId, $currentStartTime, $currentEndTime),
+            2
+        );
+
         //批发开单
         $pfIncome = 0;
         $tbSaleIncome = [];