shish 7 часов назад
Родитель
Сommit
2c3ca5dd29

+ 67 - 62
app-ghs/controllers/StatItemController.php

@@ -71,84 +71,82 @@ class StatItemController extends BaseController
         $staffId = $get['staffId'] ?? 0;
 
         $list = OrderClass::getAllByCondition($where, null, '*');
-        if (empty($list)) {
-            util::success(['list' => []]);
-        }
         $productInfo = ProductClass::getAllByCondition(['mainId' => $this->mainId], null, 'id,name,py,cgStaffId', 'id');
         $stat = [];
         $totalAmount = 0;
         $totalNum = 0;
         $totalMl = 0;
-        foreach ($list as $order) {
-            $orderSn = $order['orderSn'] ?? '';
-            $status = $order['status'] ?? 0;
-            $book = $order['book'] ?? 0;
-            $actPrice = $order['actPrice'] ?? 0;
-            if ($status == 5 || $status == 1 || ($book == 1 && $status == 2)) {
-                continue;
-            }
-            if ($actPrice <= 0) {
-                //如果全部退款的花材也不统计
-                continue;
-            }
-            $itemList = OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
-            if (!empty($itemList)) {
-                foreach ($itemList as $item) {
-                    $productId = $item->productId ?? 0;
-                    $name = $productInfo[$productId]['name'] ?? '';
-                    $py = $productInfo[$productId]['py'] ?? '';
+        if (!empty($list)) {
+            foreach ($list as $order) {
+                $orderSn = $order['orderSn'] ?? '';
+                $status = $order['status'] ?? 0;
+                $book = $order['book'] ?? 0;
+                $actPrice = $order['actPrice'] ?? 0;
+                if ($status == 5 || $status == 1 || ($book == 1 && $status == 2)) {
+                    continue;
+                }
+                if ($actPrice <= 0) {
+                    //如果全部退款的花材也不统计
+                    continue;
+                }
+                $itemList = OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
+                if (!empty($itemList)) {
+                    foreach ($itemList as $item) {
+                        $productId = $item->productId ?? 0;
+                        $name = $productInfo[$productId]['name'] ?? '';
+                        $py = $productInfo[$productId]['py'] ?? '';
 
-                    if (!empty($staffId)) {
-                        $currentCgStaffId = $productInfo[$productId]['cgStaffId'] ?? 0;
-                        if ($staffId != $currentCgStaffId) {
-                            continue;
+                        if (!empty($staffId)) {
+                            $currentCgStaffId = $productInfo[$productId]['cgStaffId'] ?? 0;
+                            if ($staffId != $currentCgStaffId) {
+                                continue;
+                            }
                         }
-                    }
 
-                    $num = NextDayRefundClass::payDayRemainNum(
-                        $item['xhNum'] ?? 0,
-                        $item['refundNum'] ?? 0,
-                        $item['nextRefundNum'] ?? 0
-                    );
-                    $unitPrice = $item['xhUnitPrice'] ?? 0;
-                    $unitCost = $item['cost'] ?? 0;
-                    $unitGross = bcsub($unitPrice, $unitCost, 2);
-                    $currentAmount = bcmul($unitPrice, $num, 2);
-                    $currentGross = bcmul($unitGross, $num, 2);
+                        $num = NextDayRefundClass::payDayRemainNum(
+                            $item['xhNum'] ?? 0,
+                            $item['refundNum'] ?? 0,
+                            $item['nextRefundNum'] ?? 0
+                        );
+                        $unitPrice = $item['xhUnitPrice'] ?? 0;
+                        $unitCost = $item['cost'] ?? 0;
+                        $unitGross = bcsub($unitPrice, $unitCost, 2);
+                        $currentAmount = bcmul($unitPrice, $num, 2);
+                        $currentGross = bcmul($unitGross, $num, 2);
 
-                    $totalNum = bcadd($totalNum, $num, 2);
-                    $totalAmount = bcadd($totalAmount, $currentAmount, 2);
+                        $totalNum = bcadd($totalNum, $num, 2);
+                        $totalAmount = bcadd($totalAmount, $currentAmount, 2);
 
-                    $totalMl = bcadd($totalMl, $currentGross, 2);
+                        $totalMl = bcadd($totalMl, $currentGross, 2);
 
-                    if ($currentGross < 0) {
-                        //noticeUtil::push($item->id . ' 毛利是负的', '15280215347');
-                    }
+                        if ($currentGross < 0) {
+                            //noticeUtil::push($item->id . ' 毛利是负的', '15280215347');
+                        }
 
-                    $stat[$productId]['productId'] = $productId;
-                    $stat[$productId]['name'] = $name;
-                    $stat[$productId]['py'] = $py;
-                    if (isset($stat[$productId]['num'])) {
-                        $stat[$productId]['num'] = bcadd($stat[$productId]['num'], $num, 2);
-                    } else {
-                        $stat[$productId]['num'] = $num;
-                    }
-                    if (isset($stat[$productId]['amount'])) {
-                        $stat[$productId]['amount'] = bcadd($stat[$productId]['amount'], $currentAmount, 2);
-                    } else {
-                        $stat[$productId]['amount'] = $currentAmount;
-                    }
-                    if (isset($stat[$productId]['gross'])) {
-                        $stat[$productId]['gross'] = bcadd($stat[$productId]['gross'], $currentGross, 2);
-                    } else {
-                        $stat[$productId]['gross'] = $currentGross;
+                        $stat[$productId]['productId'] = $productId;
+                        $stat[$productId]['name'] = $name;
+                        $stat[$productId]['py'] = $py;
+                        if (isset($stat[$productId]['num'])) {
+                            $stat[$productId]['num'] = bcadd($stat[$productId]['num'], $num, 2);
+                        } else {
+                            $stat[$productId]['num'] = $num;
+                        }
+                        if (isset($stat[$productId]['amount'])) {
+                            $stat[$productId]['amount'] = bcadd($stat[$productId]['amount'], $currentAmount, 2);
+                        } else {
+                            $stat[$productId]['amount'] = $currentAmount;
+                        }
+                        if (isset($stat[$productId]['gross'])) {
+                            $stat[$productId]['gross'] = bcadd($stat[$productId]['gross'], $currentGross, 2);
+                        } else {
+                            $stat[$productId]['gross'] = $currentGross;
+                        }
                     }
                 }
             }
         }
 
-        // 通过日:退货扣数量+金额;仅退款只扣金额(按原单花材占比分摊)
-        // 支付日净销量已用 nextRefundNum(payDayRemainNum),无需再加回
+        // 通过日:退货扣数量+金额;仅退款只扣金额;无当日销量的花材也建负行
         $deductMaps = [
             NextDayRefundClass::sumItemByProduct($this->mainId, $currentStartTime, $currentEndTime),
             NextDayRefundClass::sumMoneyOnlyAmountByProduct($this->mainId, $currentStartTime, $currentEndTime),
@@ -162,7 +160,14 @@ class StatItemController extends BaseController
                     }
                 }
                 if (!isset($stat[$pid])) {
-                    continue;
+                    $stat[$pid] = [
+                        'productId' => $pid,
+                        'name' => $productInfo[$pid]['name'] ?? '',
+                        'py' => $productInfo[$pid]['py'] ?? '',
+                        'num' => '0.00',
+                        'amount' => '0.00',
+                        'gross' => '0.00',
+                    ];
                 }
                 $subNum = (string)($row['num'] ?? '0');
                 $subAmt = (string)($row['amount'] ?? '0');

+ 28 - 0
biz-ghs/order/classes/NextDayRefundClass.php

@@ -579,6 +579,34 @@ class NextDayRefundClass
         return $map;
     }
 
+    /**
+     * 按客户汇总隔天退货数量(仅退货退款;通过日无开单时客户业绩扎数可显示为负)
+     * @return array customId => num
+     */
+    public static function sumItemQtyByCustom($mainId, $startTime, $endTime)
+    {
+        $sql = "SELECT r.customId, COALESCE(SUM(i.xhNum),0) AS num
+            FROM xhRefundItem i
+            INNER JOIN xhRefund r ON r.orderSn = i.orderSn
+            WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
+              AND r.refundType=:rtype
+              AND IFNULL(NULLIF(r.passTime,'0000-00-00 00:00:00'), r.addTime) BETWEEN :start AND :end
+            GROUP BY r.customId";
+        $rows = Yii::$app->db->createCommand($sql, [
+            ':mainId' => $mainId,
+            ':status' => RefundOrderClass::STATUS_COMPLETE,
+            ':sameDay' => self::SAME_DAY_NO,
+            ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY_GOOD,
+            ':start' => $startTime,
+            ':end' => $endTime,
+        ])->queryAll();
+        $map = [];
+        foreach ($rows as $row) {
+            $map[$row['customId']] = bcadd($row['num'] ?? '0', '0', 2);
+        }
+        return $map;
+    }
+
     /**
      * 按花材汇总隔天退货数量与金额(退货退款明细)
      */

+ 85 - 37
biz-ghs/stat/classes/StatSaleClass.php

@@ -201,17 +201,39 @@ class StatSaleClass extends BaseClass
                     ];
                 }
             }
-            // 隔天售后扣客户采购金额(笔数不减)
-            $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
-            foreach ($fwdMap as $cid => $amt) {
-                if (!isset($arr[$cid])) {
-                    continue;
-                }
-                $arr[$cid]['amount'] = bcsub((string)$arr[$cid]['amount'], (string)$amt, 2);
-                $arr[$cid]['profit'] = bcsub((string)$arr[$cid]['profit'], (string)$amt, 2);
-                $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
-                $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
+        }
+        // 隔天售后:按通过日扣金额/扎数;无当日开单也建负行(笔数不减)
+        $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
+        $qtyMap = NextDayRefundClass::sumItemQtyByCustom($mainId, $currentStartTime, $currentEndTime);
+        $cidKeys = array_unique(array_merge(array_keys($fwdMap), array_keys($qtyMap)));
+        foreach ($cidKeys as $cid) {
+            $amt = $fwdMap[$cid] ?? '0';
+            $qty = $qtyMap[$cid] ?? '0';
+            if (bccomp((string)$amt, '0', 2) == 0 && bccomp((string)$qty, '0', 2) == 0) {
+                continue;
             }
+            if (!isset($arr[$cid])) {
+                $arr[$cid] = [
+                    'customId' => $cid,
+                    'customName' => $customList[$cid]['name'] ?? '',
+                    'py' => $customList[$cid]['py'] ?? '',
+                    'num' => 0,
+                    'count' => '0.00',
+                    'amount' => '0.00',
+                    'levelName' => '',
+                    'orderPrice' => 0,
+                    'tkPrice' => 0,
+                    'cost' => 0,
+                    'profit' => '0.00',
+                ];
+            }
+            $arr[$cid]['amount'] = bcsub((string)$arr[$cid]['amount'], (string)$amt, 2);
+            $arr[$cid]['profit'] = bcsub((string)$arr[$cid]['profit'], (string)$amt, 2);
+            $arr[$cid]['count'] = bcsub((string)($arr[$cid]['count'] ?? 0), (string)$qty, 2);
+            $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
+            $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
+        }
+        if (!empty($arr)) {
             $arr = arrayUtil::arraySort($arr, 'profit');
         }
         $totalAmount = floatval($totalAmount);
@@ -1471,15 +1493,14 @@ class StatSaleClass extends BaseClass
                     }
                 }
             }
-
-            // 隔天售后:数量已用 nextRefundNum;通过日再扣数量/金额
-            self::applyNextDayAdjustToSendStaffRows(
-                $arr,
-                $mainId,
-                $currentStartTime,
-                $currentEndTime
-            );
         }
+        // 隔天售后:数量已用 nextRefundNum;通过日再扣(无当日配送也建负行)
+        self::applyNextDayAdjustToSendStaffRows(
+            $arr,
+            $mainId,
+            $currentStartTime,
+            $currentEndTime
+        );
         if (!empty($arr)) {
             $arr = array_values($arr);
         }
@@ -1570,18 +1591,39 @@ class StatSaleClass extends BaseClass
                     ];
                 }
             }
-            // 隔天售后按客户扣金额后归到片区(笔数不减;无当日开单的片区不新建行)
-            $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
-            foreach ($fwdMap as $cid => $amt) {
-                $distId = $customList[$cid]['distId'] ?? 0;
-                if (!isset($arr[$distId])) {
-                    continue;
-                }
-                $arr[$distId]['amount'] = bcsub((string)$arr[$distId]['amount'], (string)$amt, 2);
-                $arr[$distId]['profit'] = bcsub((string)$arr[$distId]['profit'], (string)$amt, 2);
-                $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
-                $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
+        }
+        // 隔天售后按客户归到片区扣金额/扎数;无当日开单的片区也建负行
+        $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
+        $qtyMap = NextDayRefundClass::sumItemQtyByCustom($mainId, $currentStartTime, $currentEndTime);
+        $cidKeys = array_unique(array_merge(array_keys($fwdMap), array_keys($qtyMap)));
+        foreach ($cidKeys as $cid) {
+            $amt = $fwdMap[$cid] ?? '0';
+            $qty = $qtyMap[$cid] ?? '0';
+            if (bccomp((string)$amt, '0', 2) == 0 && bccomp((string)$qty, '0', 2) == 0) {
+                continue;
+            }
+            $distId = $customList[$cid]['distId'] ?? 0;
+            if (!isset($arr[$distId])) {
+                $arr[$distId] = [
+                    'distId' => $distId,
+                    'distName' => isset($distMap[$distId]) ? $distMap[$distId]['name'] : '未划片区',
+                    'num' => 0,
+                    'count' => '0.00',
+                    'amount' => '0.00',
+                    'levelName' => '',
+                    'orderPrice' => 0,
+                    'tkPrice' => 0,
+                    'cost' => 0,
+                    'profit' => '0.00',
+                ];
             }
+            $arr[$distId]['amount'] = bcsub((string)$arr[$distId]['amount'], (string)$amt, 2);
+            $arr[$distId]['profit'] = bcsub((string)$arr[$distId]['profit'], (string)$amt, 2);
+            $arr[$distId]['count'] = bcsub((string)($arr[$distId]['count'] ?? 0), (string)$qty, 2);
+            $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
+            $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
+        }
+        if (!empty($arr)) {
             $arr = arrayUtil::arraySort($arr, 'profit');
         }
         $totalAmount = floatval($totalAmount);
@@ -1614,10 +1656,7 @@ class StatSaleClass extends BaseClass
                 if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
                     continue;
                 }
-                // 通过日扣减时:当日无该花材开单则不新建行(与花材销量一致)
-                if ($sign < 0 && !isset($arr[$pid])) {
-                    continue;
-                }
+                // 通过日扣减:当日无该花材开单也建负行(收入/数量可为负)
                 if (!isset($arr[$pid])) {
                     $arr[$pid] = [
                         'name' => $productList[$pid]['name'] ?? '已删除',
@@ -1648,7 +1687,7 @@ class StatSaleClass extends BaseClass
 
     /**
      * 配送业绩:支付日数量已用 nextRefundNum;通过日再扣数量/金额(仅退款只减金额)。
-     * 仅调整当日已有配送员行,不因纯售后新建行。
+     * 无当日配送单的配送员也会建负行业绩行。
      *
      * @param array $arr sendStaffId => 业绩行(引用修改 itemNum/amount)
      * @param int $mainId
@@ -1663,11 +1702,20 @@ class StatSaleClass extends BaseClass
     ) {
         $applyDelta = function ($staffMap, $sign) use (&$arr) {
             foreach ($staffMap as $sid => $row) {
-                if (!isset($arr[$sid])) {
-                    continue;
-                }
                 $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[$sid])) {
+                    $arr[$sid] = [
+                        'staffName' => '未记名',
+                        'orderNum' => 0,
+                        'itemNum' => '0.00',
+                        'amount' => '0.00',
+                        'staffId' => $sid,
+                    ];
+                }
                 $arr[$sid]['itemNum'] = bcadd((string)($arr[$sid]['itemNum'] ?? 0), $deltaNum, 2);
                 $arr[$sid]['amount'] = bcadd((string)($arr[$sid]['amount'] ?? 0), $deltaAmt, 2);
             }