Explorar o código

Merge branch 'after-sale' into redesign‌-260706

shish hai 6 días
pai
achega
6d1712d057

+ 2 - 1
app-ghs/controllers/OrderController.php

@@ -2678,6 +2678,7 @@ class OrderController extends BaseController
         if (isset($ext->printSn) == false || isset($ext->printKey) == false || empty($ext->printSn) || empty($ext->printKey)) {
             util::success(['hasNoPrint' => 1]);
         }
+        util::checkRepeatCommit($this->adminId, 3);
         OrderClass::onlinePrint($order, $showPrice);
         $order->printNum += 1;
         $order->save();
@@ -2842,7 +2843,7 @@ class OrderController extends BaseController
                             //返回禁止关单
                             util::fail('取消失败,如必要请强制取消');
                         }
-                    }else{
+                    } else {
                         noticeUtil::push("关单成功,订单号:{$orderSn} 原单状态:{$tradeState}", '15280215347');
                     }
                 }

+ 2 - 0
app-ghs/controllers/RefundController.php

@@ -763,6 +763,8 @@ class RefundController extends BaseController
                         'orderSn' => $refundInfo->orderSn ?? '',
                         'sameDay' => intval($refundInfo->sameDay ?? 1),
                         'fundType' => intval($refundInfo->fundType ?? 0),
+                        'onlinePay' => intval($refundInfo->onlinePay ?? 0),
+                        'payWay' => intval($refundInfo->payWay ?? 0),
                         'refundPrice' => $refundInfo->refundPrice ?? 0,
                         'customId' => intval($order->customId ?? 0),
                         'customName' => $custom->name ?? ($order->customName ?? ''),

+ 2 - 1
app-ghs/controllers/TestController.php

@@ -488,7 +488,8 @@ class TestController extends BaseController
             //['name' => '亳州花鲜谷', 'merchantNo' => '82238105992004A', 'wx' => [908947821, 908946480], 'zfb' => '2088780700742980'],
             //['name' => '福建清流美朵花业', 'merchantNo' => '82239505992002F', 'wx' => [909185571, 2000017120], 'zfb' => '2088780716665741'],
             //['name' => '东莞丰行', 'merchantNo' => '8226020599200RW', 'wx' => [909917474, 909917851], 'zfb' => '2088780774491467'],
-            ['name' => '商丘花鲜谷鲜花', 'merchantNo' => '82250605992009Q', 'wx' => [911392567, 911392641], 'zfb' => '2088780883539375'],
+            //['name' => '商丘花鲜谷鲜花', 'merchantNo' => '82250605992009Q', 'wx' => [911392567, 911392641], 'zfb' => '2088780883539375'],
+            ['name' => '东莞我要花', 'merchantNo' => '8226020599200S3', 'wx' => [913207533, 913206368], 'zfb' => '2088880020992882'],
             //['name' => '中山淘花里小榄店', 'merchantNo' => '8226030599200D5', 'wx' => [911061554, 911061963], 'zfb' => '2088780851935068'],
             //['name' => '重庆大金地', 'merchantNo' => '8226900599201GA', 'wx' => [910648990, 910644127], 'zfb' => '2088780830897617'],
             //['name' => '云南珑松珠海店', 'merchantNo' => '82258505992009Q', 'wx' => [910384498, 910385532], 'zfb' => '2088780804010303'],

+ 9 - 0
app-hd/controllers/CgRefundController.php

@@ -237,6 +237,15 @@ class CgRefundController extends BaseController
         if (empty($refund)) {
             util::fail('没有退款信息');
         }
+        // 详情「返回方式」优先用售后单资金快照;历史单无字段时回落采购原单
+        $refundPayWay = $refund['payWay'] ?? ($refund->payWay ?? null);
+        $refundOnlinePay = $refund['onlinePay'] ?? ($refund->onlinePay ?? null);
+        if (($refundPayWay === null || $refundPayWay === '') && !empty($cg)) {
+            $refund['payWay'] = is_array($cg) ? ($cg['payWay'] ?? 0) : ($cg->payWay ?? 0);
+        }
+        if (($refundOnlinePay === null || $refundOnlinePay === '') && !empty($cg)) {
+            $refund['onlinePay'] = is_array($cg) ? ($cg['onlinePay'] ?? 0) : ($cg->onlinePay ?? 0);
+        }
         $orderSn = $refund['orderSn'] ?? '';
         $cgItemList = CgRefundItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*');
         if (!empty($cgItemList)) {

+ 32 - 5
biz-ghs/custom/classes/CustomClass.php

@@ -9,6 +9,7 @@ use bizGhs\book\classes\BookCustomClass;
 use bizGhs\book\classes\BookItemCustomClass;
 use bizGhs\custom\classes\AccountMoneyClass;
 use bizGhs\custom\models\Custom;
+use bizGhs\custom\services\GhsRechargeSettleService;
 use bizGhs\ghs\classes\GhsBalanceChangeClass;
 use bizGhs\shop\classes\MainClass;
 use bizGhs\shop\classes\ShopMoneyClass;
@@ -697,7 +698,8 @@ class CustomClass extends BaseClass
     }
 
     /**
-     * 隔天冲销返充余额:成对账户加余额,不改订单 actPrice;流水挂售后单。
+     * 隔天冲销/无原单返充余额:成对账户加余额,不改订单 actPrice;流水挂售后单。
+     * 入账后按本次金额 FIFO 销挂账(与客户详情充值消欠一致)。
      * 调用方须已 lockAccountPair。
      */
     public static function nextDayRefundReturnBalance($custom, $ghs, $refund, $order)
@@ -711,7 +713,9 @@ class CustomClass extends BaseClass
         if (bccomp($refundPrice, '0', 2) <= 0) {
             util::fail('返充金额必须大于0');
         }
-        $newBalance = bcadd((string)($custom->balance ?? '0'), $refundPrice, 2);
+        // 入账前净余额:供 FIFO 结账单 payWay 判定
+        $balanceBefore = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        $newBalance = bcadd($balanceBefore, $refundPrice, 2);
         self::savePairBalanceAfterDeduct($custom, $ghs, $newBalance);
 
         $refundSn = $refund->orderSn ?? '';
@@ -743,12 +747,15 @@ class CustomClass extends BaseClass
             'remark' => '',
         ], true);
         self::addGhsRefundBalanceChange($custom, $ghs, $refund, $order, $refundPrice, $newBalance);
-        return $newBalance;
+        // 有挂账欠款时:本次返充金额去消欠(与充值 merchantRechargeWithAutoClear 一致)
+        self::fifoClearAfterRefundCredit($custom, $ghs, $refund, $refundPrice, $balanceBefore);
+        $custom = CustomClass::getById(intval($custom->id ?? 0), true);
+        return bcadd((string)($custom->balance ?? $newBalance), '0', 2);
     }
 
     /**
      * 花店采购余额付售后:成对账户原路退回(与 payToChangeBalance 对称)。
-     * 调用方须已 lockAccountPair;同时写客户余额明细与 xhGhs 余额明细(hdApp 可查)
+     * 钱退回余额后同样 FIFO 销挂账;调用方须已 lockAccountPair。
      */
     public static function refundBalancePayToPair($custom, $ghs, $refund, $order)
     {
@@ -761,7 +768,8 @@ class CustomClass extends BaseClass
         if (bccomp($refundPrice, '0', 2) <= 0) {
             return;
         }
-        $newBalance = bcadd((string)($custom->balance ?? '0'), $refundPrice, 2);
+        $balanceBefore = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        $newBalance = bcadd($balanceBefore, $refundPrice, 2);
         self::savePairBalanceAfterDeduct($custom, $ghs, $newBalance);
 
         $relateId = $refund->id ?? 0;
@@ -793,6 +801,25 @@ class CustomClass extends BaseClass
         ];
         CustomBalanceChangeClass::add($change, true);
         self::addGhsRefundBalanceChange($custom, $ghs, $refund, $order, $refundPrice, $newBalance);
+        // 余额付原路退回 = 加余额,有挂账时一并消欠
+        self::fifoClearAfterRefundCredit($custom, $ghs, $refund, $refundPrice, $balanceBefore);
+    }
+
+    /**
+     * 售后加余额后的 FIFO 销挂账封装:组装门店/操作人后交给 GhsRechargeSettleService。
+     */
+    protected static function fifoClearAfterRefundCredit($custom, $ghs, $refund, $amount, $balanceBefore)
+    {
+        $shopId = intval($refund->shopId ?? 0);
+        $shop = $shopId > 0 ? ShopClass::getById($shopId, true) : null;
+        $staff = (object)[
+            'id' => intval($refund->shopAdminId ?? 0),
+            'name' => (string)($refund->shopAdminName ?? ''),
+        ];
+        GhsRechargeSettleService::afterCreditFifoClear($custom, $ghs, $amount, $shop, $staff, [
+            'balanceBeforeRecharge' => $balanceBefore,
+            'payWay' => dict::getDict('payWay', 'balancePay'),
+        ]);
     }
 
     /** 花店采购余额退款:记 xhGhs 余额变动(与 addGhsOrderBalanceChange 对称,hdApp 余额明细展示) */

+ 53 - 1
biz-ghs/custom/services/GhsRechargeSettleService.php

@@ -9,6 +9,7 @@ use bizGhs\custom\classes\CustomClass;
 use bizGhs\ghs\classes\GhsBalanceChangeClass;
 use bizGhs\order\classes\OrderClearClass;
 use bizGhs\order\classes\OrderClass;
+use bizGhs\shop\classes\ShopClass;
 use common\components\dict;
 use common\components\noticeUtil;
 use common\components\util;
@@ -23,7 +24,7 @@ use common\components\util;
  * 4. 用账面正余额销账:无来款,FIFO 后 balance -= 实销额,可记「结账」流水。
  *
  * 入口:merchantRechargeWithAutoClear / onlinePayFifoClear / confirmClearBillWithIncoming /
- *       consumePositiveBalanceFifo
+ *       consumePositiveBalanceFifo / afterCreditFifoClear
  */
 class GhsRechargeSettleService
 {
@@ -178,6 +179,57 @@ class GhsRechargeSettleService
         return true;
     }
 
+    /**
+     * 售后等「已入账」来款后的 FIFO 销挂账(对齐客户详情充值消欠)。
+     * 调用时机:余额已加完;本方法只用本次金额作资金池销 remainDebtPrice,不再扣 balance。
+     * 场景:隔天/无原单返充余额、当天余额付原路退回。
+     *
+     * @param object $custom 客户
+     * @param object|null $ghs 成对供货商账户,空则按 custom.ghsId 加锁
+     * @param string|float $amount 本次入账金额
+     * @param object|null $shop 供货商门店;空则取 ghs.shopId
+     * @param object|null $staff 操作人(结账单记录用)
+     * @param array $options balanceBeforeRecharge|payWay
+     * @return array 与 fifoSettleWithPool 相同结构
+     */
+    public static function afterCreditFifoClear($custom, $ghs, $amount, $shop = null, $staff = null, $options = [])
+    {
+        $pair = self::lockAccountPair($custom, $ghs);
+        $pool = self::money($amount);
+        if (bccomp($pool, '0', 2) <= 0) {
+            return self::emptyAllocateResult($pair['custom'], $pair['ghs']);
+        }
+
+        if (empty($shop)) {
+            $ghsShopId = intval($pair['ghs']->shopId ?? 0);
+            $shop = ShopClass::getById($ghsShopId, true);
+        }
+        if (empty($shop)) {
+            util::fail('没有找到供货商门店,无法销挂账');
+        }
+
+        // 未传则用「当前余额 - 本次入账」还原入账前净余额,供结账单 payWay/onlinePay 判定
+        if (!array_key_exists('balanceBeforeRecharge', $options)) {
+            $options['balanceBeforeRecharge'] = bcsub(
+                self::money($pair['custom']->balance ?? 0),
+                $pool,
+                2
+            );
+        }
+        if (!isset($options['payWay'])) {
+            $options['payWay'] = dict::getDict('payWay', 'balancePay');
+        }
+        if (!isset($options['rechargeSource'])) {
+            $options['rechargeSource'] = 'merchant';
+        }
+        // 钱已进余额,销账不再二次扣减
+        $options['deduct_balance'] = false;
+
+        self::voidAwaitPayClearBills($pair['custom']->id ?? 0);
+
+        return self::fifoSettleWithPool($pair, $shop, $staff, $pool, $options);
+    }
+
     /**
      * FIFO 分配计划:按订单 id 升序,资金池用尽即停止。
      *

+ 149 - 12
biz-ghs/order/services/NextDayRefundService.php

@@ -1,8 +1,8 @@
 <?php
 /**
- * 隔天售后(冲销辅助服务
- * 用途:资格校验、资金方式解析、隔天通过后的金额缓存与返余额;不建独立冲销表
- * 对应:xhRefund/xhCgRefund.sameDay=0,订单 nextDayTkPrice 累计且不改 actPrice
+ * 售后资金/隔天冲销辅助服务
+ * 用途:资格校验、资金快照(fundType/onlinePay/payWay)、隔天通过后的金额与返余额
+ * 字段:sameDay 区分当天/隔天;fundType 当天隔天通用;onlinePay/payWay 落在售后单上
  */
 namespace bizGhs\order\services;
 
@@ -25,10 +25,16 @@ class NextDayRefundService
     const SAME_DAY_YES = 1;
     const SAME_DAY_NO = 0;
 
+    /** 资金未确认 */
     const FUND_UNUSED = 0;
+    /** 原路退回 */
     const FUND_ORIGINAL = 1;
+    /** 返充到余额 */
     const FUND_BALANCE = 2;
+    /** 线下自行转账(原「仅记账」) */
     const FUND_NONE = 3;
+    /** 与 FUND_NONE 同义,便于语义阅读 */
+    const FUND_OFFLINE = 3;
 
     /**
      * 是否有有效支付时间(售后唯一时间依据;无支付时间不能售后)
@@ -117,13 +123,54 @@ class NextDayRefundService
     }
 
     /**
-     * 解析隔天资金方式:挂账/余额强制返余额;在线可选原路/返余额/仅记账。
-     * $hasRelateOrder=false 表示无原单退款(工作台「退款」),不可原路退。
+     * 原单是否为微信/支付宝线上支付(隔天也可原路退回的前提)
+     */
+    public static function isOnlinePayOrder($order)
+    {
+        if (empty($order)) {
+            return false;
+        }
+        $payWay = intval($order->payWay ?? 0);
+        $onlinePay = intval($order->onlinePay ?? dict::getDict('onlinePay', 'not'));
+        $wxPay = dict::getDict('payWay', 'wxPay');
+        $aliPay = dict::getDict('payWay', 'alipay');
+        return $onlinePay == dict::getDict('onlinePay', 'yes')
+            && in_array($payWay, [$wxPay, $aliPay], true);
+    }
+
+    /**
+     * 隔天售后未选手选资金时的默认值:线上默认原路,其它默认返余额。
+     */
+    public static function defaultNextDayFundType($order)
+    {
+        return self::isOnlinePayOrder($order) ? self::FUND_ORIGINAL : self::FUND_BALANCE;
+    }
+
+    /**
+     * 当天售后未选手选资金时的默认值:线上原路;余额/挂账返余额;线下默认线下转账。
+     */
+    public static function defaultSameDayFundType($order)
+    {
+        if (self::isOnlinePayOrder($order)) {
+            return self::FUND_ORIGINAL;
+        }
+        $payWay = intval($order->payWay ?? 0);
+        $balancePay = dict::getDict('payWay', 'balancePay');
+        $debtPay = dict::getDict('payWay', 'debtPay');
+        if ($payWay === $balancePay || $payWay === $debtPay) {
+            return self::FUND_BALANCE;
+        }
+        return self::FUND_NONE;
+    }
+
+    /**
+     * 解析资金方式(当天/隔天通用):挂账/余额强制返余额;线上可选原路/返余额/线下转账。
+     * $hasRelateOrder=false 表示无原单退款,不可原路退。
      */
     public static function resolveFundType($fundType, $order, $hasRelateOrder = true)
     {
         $fundType = intval($fundType);
-        // 无原单:只能返余额或仅记账
+        // 无原单:只能返余额或线下自行转
         if (!$hasRelateOrder || empty($order)) {
             if ($fundType === self::FUND_ORIGINAL) {
                 util::fail('无原单退款不能原路退回');
@@ -134,27 +181,117 @@ class NextDayRefundService
             return $fundType;
         }
         $payWay = intval($order->payWay ?? 0);
-        $onlinePay = intval($order->onlinePay ?? dict::getDict('onlinePay', 'not'));
         $debtPay = dict::getDict('payWay', 'debtPay');
         $balancePay = dict::getDict('payWay', 'balancePay');
-        $wxPay = dict::getDict('payWay', 'wxPay');
-        $aliPay = dict::getDict('payWay', 'alipay');
-        $isOnline = $onlinePay == dict::getDict('onlinePay', 'yes') && in_array($payWay, [$wxPay, $aliPay], true);
+        // 挂账/余额付款:资金落到返充余额
         if ($payWay === $debtPay || $payWay === $balancePay) {
             return self::FUND_BALANCE;
         }
-        if ($isOnline) {
+        // 线上付款:可选原路 / 返余额 / 线下转账
+        if (self::isOnlinePayOrder($order)) {
             if (!in_array($fundType, [self::FUND_ORIGINAL, self::FUND_BALANCE, self::FUND_NONE], true)) {
                 util::fail('请选择资金处理方式');
             }
             return $fundType;
         }
+        // 线下付款:返余额或线下自行转账
         if (!in_array($fundType, [self::FUND_BALANCE, self::FUND_NONE], true)) {
             return self::FUND_BALANCE;
         }
         return $fundType;
     }
 
+    /**
+     * 生成写入售后单的资金快照:fundType + onlinePay + payWay(落 xhRefund/xhCgRefund)。
+     * onlinePay:原路且走线上通道为 2,否则 1;payWay:原路/线下转账的具体渠道。
+     *
+     * @param int $fundTypeInput 前端/上游传入,0 表示按 sameDay 自动默认
+     * @param object|null $order 原销售单;无原单传 null
+     * @param bool $hasRelateOrder 是否有关联原单
+     * @param array $options sameDay、payWay(线下转账选手选渠道)
+     * @return array{fundType:int,onlinePay:int,payWay:int}
+     */
+    public static function buildRefundFundSnapshot($fundTypeInput, $order = null, $hasRelateOrder = true, $options = [])
+    {
+        $fundTypeInput = intval($fundTypeInput);
+        $sameDay = intval($options['sameDay'] ?? self::SAME_DAY_YES);
+        $onlineNot = intval(dict::getDict('onlinePay', 'not'));
+        $onlineYes = intval(dict::getDict('onlinePay', 'yes'));
+
+        if ($fundTypeInput === self::FUND_UNUSED && $hasRelateOrder && !empty($order)) {
+            $fundTypeInput = ($sameDay === self::SAME_DAY_NO)
+                ? self::defaultNextDayFundType($order)
+                : self::defaultSameDayFundType($order);
+        }
+
+        $fundType = self::resolveFundType($fundTypeInput, $order, $hasRelateOrder);
+
+        // 返充余额:渠道固定为余额,非线上原路
+        if ($fundType === self::FUND_BALANCE) {
+            return [
+                'fundType' => self::FUND_BALANCE,
+                'onlinePay' => $onlineNot,
+                'payWay' => intval(dict::getDict('payWay', 'balancePay')),
+            ];
+        }
+
+        // 线下自行转账:优先用选手选 payWay(微信/支付宝/现金/银行卡)
+        if ($fundType === self::FUND_NONE) {
+            $payWay = self::normalizeOfflinePayWay($options['payWay'] ?? null, $order);
+            return [
+                'fundType' => self::FUND_NONE,
+                'onlinePay' => $onlineNot,
+                'payWay' => $payWay,
+            ];
+        }
+
+        // 原路退回:线上微信/支付宝标记 onlinePay=2;否则记线下原路渠道
+        if ($fundType === self::FUND_ORIGINAL && !empty($order)) {
+            $orderPayWay = intval($order->payWay ?? 0);
+            if (self::isOnlinePayOrder($order)) {
+                return [
+                    'fundType' => self::FUND_ORIGINAL,
+                    'onlinePay' => $onlineYes,
+                    'payWay' => $orderPayWay,
+                ];
+            }
+            return [
+                'fundType' => self::FUND_ORIGINAL,
+                'onlinePay' => $onlineNot,
+                'payWay' => $orderPayWay,
+            ];
+        }
+
+        return [
+            'fundType' => self::FUND_UNUSED,
+            'onlinePay' => $onlineNot,
+            'payWay' => 0,
+        ];
+    }
+
+    /**
+     * 线下转账渠道:允许 0微信/1支付宝/4现金/5银行卡;非法则回落原单或现金
+     */
+    protected static function normalizeOfflinePayWay($payWay, $order = null)
+    {
+        $allowed = [
+            intval(dict::getDict('payWay', 'wxPay')),
+            intval(dict::getDict('payWay', 'alipay')),
+            intval(dict::getDict('payWay', 'cash')),
+            intval(dict::getDict('payWay', 'bankCard')),
+        ];
+        if ($payWay !== null && $payWay !== '' && in_array(intval($payWay), $allowed, true)) {
+            return intval($payWay);
+        }
+        if (!empty($order)) {
+            $orderPayWay = intval($order->payWay ?? -1);
+            if (in_array($orderPayWay, $allowed, true)) {
+                return $orderPayWay;
+            }
+        }
+        return intval(dict::getDict('payWay', 'cash'));
+    }
+
     /**
      * GHS 侧隔天通过:累计 nextDayTkPrice,按 fundType 处理资金,不改 actPrice。
      * @return string 返余额后的客户余额(非返余额则为当前余额)
@@ -186,7 +323,7 @@ class NextDayRefundService
             $custom = CustomClass::getById($customId, true);
             $balance = bcadd((string)($custom->balance ?? '0'), '0', 2);
         }
-        // FUND_ORIGINAL:网关退款在采购侧 CgRefundClass 执行;FUND_NONE:仅记账
+        // FUND_ORIGINAL:网关退款在采购侧执行;FUND_NONE:线下自行转账(只记账)
         return $balance;
     }
 

+ 6 - 2
biz-ghs/order/services/OrderService.php

@@ -1008,9 +1008,11 @@ class OrderService extends BaseService
             'cause' => $cause,
             'refundSendCost' => $refundSendCost,
             'refundPackCost' => $refundPackCost,
-            // 与销售侧售后成对写入隔天标记
+            // 与销售侧售后成对写入 sameDay + 资金快照
             'sameDay' => $saleRefund->sameDay ?? \bizGhs\order\classes\RefundOrderClass::SAME_DAY_YES,
             'fundType' => $saleRefund->fundType ?? 0,
+            'onlinePay' => $saleRefund->onlinePay ?? 0,
+            'payWay' => $saleRefund->payWay ?? 0,
         ];
         $cgRefund = CgRefundService::addRefund($cgData, $cg);
         $cgRefundId = $cgRefund->id;
@@ -1020,7 +1022,9 @@ class OrderService extends BaseService
         $cgRefund->saleRefundId = $saleRefundId;
         $cgRefund->sameDay = intval($saleRefund->sameDay ?? 1);
         $cgRefund->fundType = intval($saleRefund->fundType ?? 0);
-        $cgRefund->save();
+        $cgRefund->onlinePay = intval($saleRefund->onlinePay ?? 0);
+        $cgRefund->payWay = intval($saleRefund->payWay ?? 0);
+        $cgRefund->save(false, ['saleRefundId', 'sameDay', 'fundType', 'onlinePay', 'payWay']);
 
         return $saleRefund;
     }

+ 49 - 39
biz-ghs/order/services/RefundOrderService.php

@@ -134,27 +134,35 @@ class RefundOrderService extends BaseService
 
     /**
      * 将当天售后单转为隔天冲销类型(审核跨日/已结清时调用)
-     * 同步写销售售后单与采购售后单的 sameDay、fundType;花店申请无资金弹窗时默认返余额
+     * 同步写销售/采购售后单的 sameDay、fundType、onlinePay、payWay
      */
     public static function convertRefundToNextDay($refund, $order)
     {
-        $fundType = intval($refund->fundType ?? 0);
-        if ($fundType === NextDayRefundService::FUND_UNUSED) {
-            $fundType = NextDayRefundService::FUND_BALANCE;
-        }
-        $fundType = NextDayRefundService::resolveFundType($fundType, $order, true);
+        $snap = NextDayRefundService::buildRefundFundSnapshot(
+            intval($refund->fundType ?? 0),
+            $order,
+            true,
+            [
+                'sameDay' => NextDayRefundService::SAME_DAY_NO,
+                'payWay' => $refund->payWay ?? null,
+            ]
+        );
 
         $refund->sameDay = RefundOrderClass::SAME_DAY_NO;
-        $refund->fundType = $fundType;
-        $refund->save(false, ['sameDay', 'fundType']);
+        $refund->fundType = $snap['fundType'];
+        $refund->onlinePay = $snap['onlinePay'];
+        $refund->payWay = $snap['payWay'];
+        $refund->save(false, ['sameDay', 'fundType', 'onlinePay', 'payWay']);
 
         $cgRefundId = intval($refund->cgRefundId ?? 0);
         if ($cgRefundId > 0) {
             $cgRefund = CgRefundClass::getById($cgRefundId, true);
             if (!empty($cgRefund)) {
                 $cgRefund->sameDay = CgRefundClass::SAME_DAY_NO;
-                $cgRefund->fundType = $fundType;
-                $cgRefund->save(false, ['sameDay', 'fundType']);
+                $cgRefund->fundType = $snap['fundType'];
+                $cgRefund->onlinePay = $snap['onlinePay'];
+                $cgRefund->payWay = $snap['payWay'];
+                $cgRefund->save(false, ['sameDay', 'fundType', 'onlinePay', 'payWay']);
             }
         }
     }
@@ -268,7 +276,7 @@ class RefundOrderService extends BaseService
 
         // 无支付时间不能售后
         NextDayRefundService::assertCanRefund($order);
-        // 隔天冲销:sameDay=0 + fundType;非当天/已结清强制冲销(即使创建时未传 sameDay)
+        // sameDay:非当天/已结清强制隔天;资金快照当天/隔天都写入 fundType/onlinePay/payWay
         $sameDay = intval($post['sameDay'] ?? RefundOrderClass::SAME_DAY_YES);
         if (NextDayRefundService::mustUseNextDay($order)) {
             $sameDay = RefundOrderClass::SAME_DAY_NO;
@@ -278,18 +286,20 @@ class RefundOrderService extends BaseService
             if (empty($check['ok'])) {
                 util::fail($check['reason'] ?? '当前订单不可隔天冲销');
             }
-            $fundTypeInput = intval($post['fundType'] ?? 0);
-            // 未选手选资金时默认返余额(商家弹窗会覆盖;漏传/花店申请兜底)
-            if ($fundTypeInput === NextDayRefundService::FUND_UNUSED) {
-                $fundTypeInput = NextDayRefundService::FUND_BALANCE;
-            }
-            $fundType = NextDayRefundService::resolveFundType($fundTypeInput, $order, true);
-            $data['sameDay'] = RefundOrderClass::SAME_DAY_NO;
-            $data['fundType'] = $fundType;
-        } else {
-            $data['sameDay'] = RefundOrderClass::SAME_DAY_YES;
-            $data['fundType'] = NextDayRefundService::FUND_UNUSED;
         }
+        $snap = NextDayRefundService::buildRefundFundSnapshot(
+            intval($post['fundType'] ?? 0),
+            $order,
+            true,
+            [
+                'sameDay' => $sameDay,
+                'payWay' => $post['payWay'] ?? null,
+            ]
+        );
+        $data['sameDay'] = $sameDay;
+        $data['fundType'] = $snap['fundType'];
+        $data['onlinePay'] = $snap['onlinePay'];
+        $data['payWay'] = $snap['payWay'];
 
         $refund = RefundOrderClass::add($data, true);
         return $refund;
@@ -331,32 +341,28 @@ class RefundOrderService extends BaseService
             $refundType = intval($post['refundType'] ?? RefundOrderClass::REFUND_TYPE_MONEY_GOOD);
         }
 
-        // 前端 toBalance:1返充余额→fundType2;0否→仅记账3
+        // 前端 toBalance:1返充余额→fundType2;0否→线下自行转账3
         $toBalance = intval($post['toBalance'] ?? -1);
         if ($toBalance === 1) {
             $post['fundType'] = NextDayRefundService::FUND_BALANCE;
         } elseif ($toBalance === 0) {
             $post['fundType'] = NextDayRefundService::FUND_NONE;
         }
-        $fundType = NextDayRefundService::resolveFundType($post['fundType'] ?? 0, null, false);
+        // 无原单:写入 fundType/onlinePay/payWay(payWay 为线下转账渠道)
+        $snap = NextDayRefundService::buildRefundFundSnapshot(
+            intval($post['fundType'] ?? 0),
+            null,
+            false,
+            [
+                'sameDay' => NextDayRefundService::SAME_DAY_NO,
+                'payWay' => $post['payWay'] ?? null,
+            ]
+        );
 
         $sjId = intval($post['sjId'] ?? 0);
         $shopId = intval($post['shopId'] ?? 0);
         $orderSn = orderSn::getGhsRefundSn();
-
-        // xhRefund 暂无 payWay 字段:退款方式写入备注便于追溯
-        $payWay = intval($post['payWay'] ?? -1);
-        $payWayNameMap = [
-            0 => '线下微信',
-            1 => '线下支付宝',
-            4 => '现金',
-            5 => '银行卡',
-        ];
         $remark = trim((string)($post['remark'] ?? ''));
-        if (isset($payWayNameMap[$payWay])) {
-            $payTag = '退款方式:' . $payWayNameMap[$payWay];
-            $remark = $remark === '' ? $payTag : ($remark . ';' . $payTag);
-        }
 
         $data = [
             'status' => RefundOrderClass::STATUS_UN_COMPLETE,
@@ -380,7 +386,9 @@ class RefundOrderService extends BaseService
             'refundPrice' => $refundPrice,
             'refundType' => $refundType,
             'sameDay' => RefundOrderClass::SAME_DAY_NO,
-            'fundType' => $fundType,
+            'fundType' => $snap['fundType'],
+            'onlinePay' => $snap['onlinePay'],
+            'payWay' => $snap['payWay'],
         ];
 
         $postProduct = $post['product'] ?? [];
@@ -455,7 +463,9 @@ class RefundOrderService extends BaseService
             'id' => intval($refund->id ?? 0),
             'orderSn' => $refund->orderSn ?? '',
             'sameDay' => RefundOrderClass::SAME_DAY_NO,
-            'fundType' => intval($refund->fundType ?? $fundType),
+            'fundType' => intval($refund->fundType ?? $snap['fundType']),
+            'onlinePay' => intval($refund->onlinePay ?? $snap['onlinePay']),
+            'payWay' => intval($refund->payWay ?? $snap['payWay']),
             'refundPrice' => $refund->refundPrice ?? $refundPrice,
             'customId' => $customId,
             'customName' => $custom->name ?? ($refund->customName ?? ''),

+ 4 - 2
biz-hd/cg/classes/CgRefundClass.php

@@ -41,11 +41,12 @@ class CgRefundClass extends BaseClass
 
     /**
      * 隔天冲销原路退:走拉卡拉退款,不改采购单 actPrice
+     * 优先读售后单资金快照 onlinePay/payWay,缺省回落采购原单
      */
     public static function nextDayOriginalOnlineRefund($cgRefund, $cg)
     {
-        $onlinePay = $cg->onlinePay ?? 1;
-        $payWay = $cg->payWay ?? 0;
+        $onlinePay = $cgRefund->onlinePay ?? ($cg->onlinePay ?? 1);
+        $payWay = $cgRefund->payWay ?? ($cg->payWay ?? 0);
         if ($onlinePay != dict::getDict('onlinePay', 'yes')) {
             util::fail('非在线支付无法原路退回');
         }
@@ -75,6 +76,7 @@ class CgRefundClass extends BaseClass
             'lklCertificatePath' => $lklCertificatePath,
         ];
         $laResource = new Lakala($params);
+        // 流水号策略暂维持售后单号;唯一性撞号问题另行处理
         $refundOrderSn = $cgRefund->orderSn ?? orderSn::getCgRefundSn();
         $aliParams = [
             'refundSn' => $refundOrderSn,

+ 25 - 13
biz-hd/cg/services/CgRefundService.php

@@ -56,19 +56,25 @@ class CgRefundService extends BaseService
         // 无支付时间不能售后;仅用 payTime 判当天/隔天
         NextDayRefundService::assertCanRefund($order);
 
-        // 非当天 / 已结账 / 挂账结清 → 申请即写隔天售后;无资金弹窗时默认返余额
+        // 非当天 / 已结账 / 挂账结清 → 隔天;资金快照当天/隔天都写 fundType/onlinePay/payWay
         $sameDay = CgRefundClass::SAME_DAY_YES;
-        $fundType = NextDayRefundService::FUND_UNUSED;
         if (NextDayRefundService::mustUseNextDay($order)) {
             $sameDay = CgRefundClass::SAME_DAY_NO;
-            $fundType = NextDayRefundService::resolveFundType(
-                NextDayRefundService::FUND_BALANCE,
-                $order,
-                true
-            );
         }
+        $snap = NextDayRefundService::buildRefundFundSnapshot(
+            intval($cgData['fundType'] ?? 0),
+            $order,
+            true,
+            [
+                'sameDay' => $sameDay,
+                'payWay' => $cgData['payWay'] ?? null,
+            ]
+        );
         $cgData['sameDay'] = $sameDay;
-        $cgData['fundType'] = $fundType;
+        $cgData['fundType'] = $snap['fundType'];
+        $cgData['onlinePay'] = $snap['onlinePay'];
+        $cgData['payWay'] = $snap['payWay'];
+        $fundType = $snap['fundType'];
 
         $respond = self::addRefund($cgData, $cg);
         $remark = $cgData['remark'] ?? '';
@@ -133,18 +139,22 @@ class CgRefundService extends BaseService
             'mainId' => $mainId,
             'product' => $newProductList,
             'sameDay' => $sameDay,
-            'fundType' => $fundType,
+            'fundType' => $snap['fundType'],
+            'onlinePay' => $snap['onlinePay'],
+            'payWay' => $snap['payWay'],
         ];
         $cgRefundId = $respond->id ?? 0;
         $saleRefund = RefundOrderService::addRefund($orderData, $order);
         $saleRefund->cgRefundId = $cgRefundId;
         $saleRefund->save();
         $saleRefundId = $saleRefund->id ?? 0;
-        // 与销售侧最终 sameDay/fundType 对齐(addRefund 内可能再次强制隔天)
+        // 与销售侧最终资金快照对齐(addRefund 内可能再次强制隔天)
         $respond->saleRefundId = $saleRefundId;
         $respond->sameDay = intval($saleRefund->sameDay ?? $sameDay);
-        $respond->fundType = intval($saleRefund->fundType ?? $fundType);
-        $respond->save();
+        $respond->fundType = intval($saleRefund->fundType ?? $snap['fundType']);
+        $respond->onlinePay = intval($saleRefund->onlinePay ?? $snap['onlinePay']);
+        $respond->payWay = intval($saleRefund->payWay ?? $snap['payWay']);
+        $respond->save(false, ['saleRefundId', 'sameDay', 'fundType', 'onlinePay', 'payWay']);
         return $respond;
     }
 
@@ -212,9 +222,11 @@ class CgRefundService extends BaseService
         $data['bigNum'] = $bigNum;
         $data['smallNum'] = $smallNum;
         $data['cause'] = $cause;
-        // 隔天冲销与销售侧成对:sameDay/fundType 由上游传入
+        // 与销售侧成对:sameDay + 资金快照由上游传入
         $data['sameDay'] = intval($post['sameDay'] ?? CgRefundClass::SAME_DAY_YES);
         $data['fundType'] = intval($post['fundType'] ?? 0);
+        $data['onlinePay'] = intval($post['onlinePay'] ?? dict::getDict('onlinePay', 'not'));
+        $data['payWay'] = intval($post['payWay'] ?? 0);
         $cgRefund = CgRefundClass::add($data, true);
 
         if ($refundType == CgRefundClass::REFUND_TYPE_MONEY_GOOD) {