Просмотр исходного кода

Merge branch 'redesign‌-260706' into dev

shish 16 часов назад
Родитель
Сommit
75de56c88b

+ 2 - 2
app-ghs/controllers/ConsoleController.php

@@ -322,8 +322,8 @@ class ConsoleController extends BaseController
 
         $warning = '';
         $warningUrl = '';
-        $warning = '挂账结清,支持售后了(重大更新,必看)';
-        $warningUrl = '/admin/notice/warning';
+        //$warning = '挂账结清,支持售后了(重大更新,必看)';
+        //$warningUrl = '/admin/notice/warning';
 
         util::success([
             'asset' => $this->main,

+ 26 - 0
app-hd/controllers/RefundController.php

@@ -110,6 +110,32 @@ class RefundController extends BaseController
         util::success(['info' => $info, 'itemList' => $itemList, 'goodsList' => $goodsList, 'productList' => $productList]);
     }
 
+    /**
+     * 原单是否可走隔天售后(售后页预检,对齐 ghs check-next-day-eligible)
+     */
+    public function actionCheckNextDayEligible()
+    {
+        $orderId = Yii::$app->request->get('orderId', 0);
+        $order = OrderClass::getById($orderId, true);
+        if (empty($order) || intval($order->mainId) !== intval($this->mainId)) {
+            util::fail('没有找到订单');
+        }
+        $main = $this->main;
+        $check = HdNextDayRefundClass::checkEligible($order, $main);
+        $check['hasPayTime'] = HdNextDayRefundClass::hasValidPayTime($order) ? 1 : 0;
+        $check['hasNextDay'] = bccomp((string)($order->nextDayTkPrice ?? '0'), '0', 2) > 0 ? 1 : 0;
+        $check['nextDayTkPrice'] = $order->nextDayTkPrice ?? '0.00';
+        $check['tkPrice'] = $order->tkPrice ?? '0.00';
+        $check['actPrice'] = $order->actPrice ?? '0.00';
+        $check['payWay'] = $order->payWay ?? 0;
+        $check['onlinePay'] = $order->onlinePay ?? 0;
+        $check['debtPrice'] = $order->debtPrice ?? '0.00';
+        $check['remainDebtPrice'] = $order->remainDebtPrice ?? '0.00';
+        $check['clearId'] = intval($order->clearId ?? 0);
+        $check['payTime'] = $order->payTime ?? '';
+        util::success($check);
+    }
+
     //退款 ssh 20220427
     public function actionCreateOrder()
     {

+ 1 - 1
biz-hd/cg/classes/CgRefundClass.php

@@ -82,7 +82,7 @@ class CgRefundClass extends BaseClass
             'refundSn' => $refundOrderSn,
             'orderSn' => $cg->orderSn ?? '',
             'refundAmount' => $refundFee,
-            'refundReason' => '隔天售后原路退回',
+            'refundReason' => '订单售后,原路退回',
             'thirdNo' => $cg->thirdNo ?? '',
         ];
         $response = $laResource->refund($aliParams);

+ 141 - 1
biz-hd/custom/classes/CustomClass.php

@@ -680,7 +680,12 @@ class CustomClass extends BaseClass
             'remark' => '',
         ];
         BalanceChangeClass::add($change, true);
-        return $customBalance;
+
+        // 返充入账后:优先结当前售后原单挂账,剩余再 FIFO(不再二次扣余额)
+        $balanceBefore = bcsub($customBalance, $amount, 2);
+        self::fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order);
+        $custom = CustomClass::getById($custom->id ?? 0, true);
+        return bcadd((string)($custom->balance ?? $customBalance), '0', 2);
     }
 
     //欠款和余额支付的售后 ssh 20250803
@@ -691,6 +696,10 @@ class CustomClass extends BaseClass
         if (empty($hd)) {
             util::fail('花店信息缺失,编号5362');
         }
+        // 入账前净余额,供结账单 payWay 判定
+        $balanceBefore = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        // 原始支付方式:后面流水会改写成余额付,FIFO 判定要用原值
+        $originPayWay = intval($payWay);
         $customBalance = bcadd($custom->balance, $amount, 2);
         $custom->balance = $customBalance;
         if ($custom->balance < 0) {
@@ -852,6 +861,137 @@ class CustomClass extends BaseClass
             }
             $order->save();
         }
+
+        // 当天挂账售后已先减 remainDebtPrice,再 FIFO 优先本单会重复销账;仅隔天/返充类或余额付原路才消欠
+        $sameDay = intval($refund->sameDay ?? 1);
+        $debtPay = intval(dict::getDict('payWay', 'debtPay'));
+        $skipFifo = ($originPayWay === $debtPay && $sameDay === 1);
+        if (!$skipFifo) {
+            self::fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order);
+        }
+    }
+
+    /**
+     * 售后返充/原路退余额后销挂账:优先当前售后原单 remainDebtPrice(可部分结),再按 id 升序 FIFO。
+     * 调用时机:余额已入账;本方法只用本次金额作资金池,不再扣 balance。
+     *
+     * @param object $custom 客户(已加锁)
+     * @param object $hd 花店账户
+     * @param object $refund 售后单
+     * @param string|float $amount 本次入账金额
+     * @param string|float $balanceBefore 入账前净余额
+     * @param object|null $order 售后关联销售单
+     */
+    protected static function fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order = null)
+    {
+        $pool = bcadd((string)$amount, '0', 2);
+        if (bccomp($pool, '0', 2) <= 0) {
+            return;
+        }
+        $customId = intval($custom->id ?? 0);
+        if ($customId <= 0) {
+            return;
+        }
+
+        $preferOrderId = !empty($order) ? intval($order->id ?? 0) : intval($refund->orderId ?? 0);
+        $plan = self::planFifoClearByPool($customId, $pool, $preferOrderId);
+        if (empty($plan)) {
+            return;
+        }
+
+        $shopId = intval($refund->shopId ?? ($custom->shopId ?? 0));
+        $shop = $shopId > 0 ? ShopClass::getById($shopId, true) : null;
+        if (empty($shop)) {
+            // 无门店无法建结账单,跳过销账(余额已入账,不阻断售后)
+            return;
+        }
+
+        $settleParams = [
+            'staffId' => intval($refund->shopAdminId ?? 0),
+            'staffName' => (string)($refund->shopAdminName ?? ''),
+        ];
+        $set = SettleClass::addSettle($plan, $shop, $custom, $hd, $settleParams);
+        if (!empty($set)) {
+            SettleClass::clearSettle($set);
+        }
+        // 刷新客户欠款标记(有未结挂账单则为欠款户)
+        $leftDebt = OrderClass::getAllByCondition(['customId' => $customId, 'debt' => 1], null, 'id', null, true);
+        $customFresh = self::getLockById($customId);
+        if (!empty($customFresh)) {
+            $customFresh->isDebt = !empty($leftDebt) ? 1 : 0;
+            $customFresh->save(false, ['isDebt']);
+        }
+    }
+
+    /**
+     * 销挂账分配:可选优先本单,剩余按订单 id 升序 FIFO。
+     * prefer 路径只用 remainDebtPrice,不用 actPrice 兜底,避免脏数据多销。
+     *
+     * @param int $customId
+     * @param string|float $poolAmount
+     * @param int $preferOrderId
+     * @return array<int, array{orderId:int, clearAmount:string, orderSn:string}>
+     */
+    protected static function planFifoClearByPool($customId, $poolAmount, $preferOrderId = 0)
+    {
+        $pool = bcadd((string)$poolAmount, '0', 2);
+        if (bccomp($pool, '0', 2) <= 0) {
+            return [];
+        }
+        $orderList = OrderClass::getAllByCondition(['customId' => $customId, 'debt' => 1], 'id asc', '*', null, true);
+        if (empty($orderList)) {
+            return [];
+        }
+
+        $plan = [];
+        $used = '0.00';
+        $preferOrderId = intval($preferOrderId);
+
+        // 1)售后原单仍挂账:先结本单(不够则部分结)
+        if ($preferOrderId > 0) {
+            foreach ($orderList as $ord) {
+                if (intval($ord->id ?? 0) !== $preferOrderId) {
+                    continue;
+                }
+                $remain = bcadd((string)($ord->remainDebtPrice ?? '0'), '0', 2);
+                if (bccomp($remain, '0', 2) <= 0) {
+                    break;
+                }
+                $clearAmount = bccomp($remain, $pool, 2) <= 0 ? $remain : $pool;
+                $plan[] = [
+                    'orderId' => $preferOrderId,
+                    'clearAmount' => $clearAmount,
+                    'orderSn' => $ord->orderSn ?? '',
+                ];
+                $used = bcadd($used, $clearAmount, 2);
+                break;
+            }
+        }
+
+        // 2)剩余金额 FIFO(跳过已优先处理的本单)
+        foreach ($orderList as $ord) {
+            $left = bcsub($pool, $used, 2);
+            if (bccomp($left, '0', 2) <= 0) {
+                break;
+            }
+            $oid = intval($ord->id ?? 0);
+            if ($preferOrderId > 0 && $oid === $preferOrderId) {
+                continue;
+            }
+            $remain = bcadd((string)($ord->remainDebtPrice ?? '0'), '0', 2);
+            if (bccomp($remain, '0', 2) <= 0) {
+                continue;
+            }
+            $clearAmount = bccomp($remain, $left, 2) <= 0 ? $remain : $left;
+            $plan[] = [
+                'orderId' => $oid,
+                'clearAmount' => $clearAmount,
+                'orderSn' => $ord->orderSn ?? '',
+            ];
+            $used = bcadd($used, $clearAmount, 2);
+        }
+
+        return $plan;
     }
 
     //添加客户 ssh 2021.2.28

+ 49 - 9
biz-hd/refund/classes/HdNextDayRefundClass.php

@@ -59,26 +59,66 @@ class HdNextDayRefundClass
      */
     public static function mustUseNextDay($order, $main = null)
     {
+        $check = self::checkEligible($order, $main);
+        return !empty($check['ok']);
+    }
+
+    /**
+     * 原单是否可走隔天售后(售后页预检,对齐 ghs NextDayRefundClass::checkEligible)
+     * @return array{ok:bool,reason:string,sameDay:int,orderCleared:int,hasPayTime:int}
+     */
+    public static function checkEligible($order, $main = null)
+    {
+        if (empty($order)) {
+            return [
+                'ok' => false,
+                'reason' => '没有原订单',
+                'sameDay' => self::SAME_DAY_YES,
+                'orderCleared' => 0,
+                'hasPayTime' => 0,
+            ];
+        }
         if (!self::hasValidPayTime($order)) {
-            return false;
+            return [
+                'ok' => false,
+                'reason' => '订单无支付时间,不能售后',
+                'sameDay' => self::SAME_DAY_YES,
+                'orderCleared' => 0,
+                'hasPayTime' => 0,
+            ];
         }
         $payTime = $order->payTime;
-        if (date('Y-m-d', strtotime($payTime)) !== date('Y-m-d')) {
-            return true;
-        }
+        $isToday = date('Y-m-d', strtotime($payTime)) === date('Y-m-d');
         $debtPay = intval(dict::getDict('payWay', 'debtPay'));
+        $debtCleared = false;
         if (intval($order->payWay ?? 0) === $debtPay) {
-            if (bccomp((string)($order->remainDebtPrice ?? '0'), '0', 2) <= 0) {
-                return true;
-            }
+            $debtCleared = bccomp((string)($order->remainDebtPrice ?? '0'), '0', 2) <= 0;
         }
+        $orderCleared = !empty($order->clearId);
+        $overTimeLimit = false;
         if (!empty($main)) {
             $cRet = OrderClass::couldRefund($order, $main);
             if (empty($cRet['could'])) {
-                return true;
+                $overTimeLimit = true;
             }
         }
-        return false;
+        // 当天且未结清、未超时 → 普通当天售后
+        if ($isToday && !$debtCleared && !$orderCleared && !$overTimeLimit) {
+            return [
+                'ok' => false,
+                'reason' => '当天未结账订单请走普通售后;已结账/挂账结清/超时/隔天可售后',
+                'sameDay' => self::SAME_DAY_YES,
+                'orderCleared' => 0,
+                'hasPayTime' => 1,
+            ];
+        }
+        return [
+            'ok' => true,
+            'reason' => '',
+            'sameDay' => self::SAME_DAY_NO,
+            'orderCleared' => ($orderCleared || $debtCleared) ? 1 : 0,
+            'hasPayTime' => 1,
+        ];
     }
 
     /**