Explorar o código

充值与销账

shish hai 2 meses
pai
achega
df1f148df2

+ 3 - 3
app-hd/controllers/PurchaseController.php

@@ -993,7 +993,7 @@ class PurchaseController extends BaseController
         if (!empty($has)) {
             util::fail('请稍等...');
         }
-        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 6, 'has']);
+        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 8, 'has']);
 
         $info = PurchaseClass::getByCondition(['orderSn' => $orderSn], true);
         if (empty($info)) {
@@ -1105,8 +1105,8 @@ class PurchaseController extends BaseController
         $connection = Yii::$app->db;
         $transaction = $connection->beginTransaction();
         try {
-            // 余额支付:走 xhGhsCustom,不扣 main.balance
-            $info = PurchaseService::balancePay($info);
+            //余额支付
+            purchaseService::balancePay($info);
             $transaction->commit();
         } catch (\Exception $e) {
             $transaction->rollBack();

+ 3 - 3
biz-ghs/custom/classes/CustomClass.php

@@ -228,7 +228,7 @@ class CustomClass extends BaseClass
 
         // 合并后净余额可为负(待结),勿再因扣款后 <0 报错;金额由 CustomPaymentAllocateService 按来款池控制
         if (bccomp($newGhsBalance, $newCustomBalance, 2) !== 0) {
-            util::fail('余额有问题,请向客服反应');
+            util::fail('客户与供货商余额不一致,无法结账,请联系管理员');
         }
 
         $ghs->balance = $newGhsBalance;
@@ -650,7 +650,7 @@ class CustomClass extends BaseClass
     }
 
     /**
-     * 调用方已 lockAccountPair 时,校验 custom/ghs 净余额一致;不一致则中止并提示联系客服
+     * 调用方已 lockAccountPair 时,校验 custom/ghs 净余额一致。
      */
     protected static function assertPairBalanceEqual($custom, $ghs)
     {
@@ -660,7 +660,7 @@ class CustomClass extends BaseClass
         $customBal = bcadd((string)($custom->balance ?? '0'), '0', 2);
         $ghsBal = bcadd((string)($ghs->balance ?? '0'), '0', 2);
         if (bccomp($customBal, $ghsBal, 2) !== 0) {
-            util::fail('余额有问题,请向客服反应');
+            util::fail('客户与供货商余额不一致,请联系管理员');
         }
     }
 

+ 11 - 1
biz-ghs/custom/classes/CustomRechargeClass.php

@@ -92,6 +92,8 @@ class CustomRechargeClass extends BaseClass
         $customStaffId = $ghsRecharge->staffId ?? 0;
         $customStaffName = $ghsRecharge->staffName ?? '';
 
+        // 入账前净余额:用于判断结账单是否纯本次线上来款销账(有历史正余额则不标 onlinePay)
+        $balanceBeforeRecharge = bcadd((string)($custom->balance ?? '0'), '0', 2);
         $custom->balance = bcadd($custom->balance, $amount, 2);
         $custom->save();
         $capitalType = dict::getDict('capitalType', 'customRechargeToGhs', 'id');
@@ -161,7 +163,15 @@ class CustomRechargeClass extends BaseClass
         // 按「本次支付金额」FIFO 销挂账并回写 clearAmount(合并后净余额模型)
         $ghsShop = ShopClass::getById($ghsShopId, true);
         if (!empty($ghsShop)) {
-            GhsRechargeSettleService::onlinePayFifoClear($custom, $ghsInfo, $ghsShop, $amount, $customRecharge, $ghsRecharge);
+            GhsRechargeSettleService::onlinePayFifoClear(
+                $custom,
+                $ghsInfo,
+                $ghsShop,
+                $amount,
+                $customRecharge,
+                $ghsRecharge,
+                $balanceBeforeRecharge
+            );
         }
 
     }

+ 114 - 8
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 common\components\dict;
 use common\components\util;
 
 /**
@@ -53,16 +54,47 @@ class GhsRechargeSettleService
         return $respond;
     }
 
-    /** 线上支付已入账后的 FIFO 销账(CustomRechargeClass::thirdPay) */
-    public static function onlinePayFifoClear($custom, $ghs, $shop, $amount, $customRecharge, $ghsRecharge = null)
+    /**
+     * 线上充值销账结账单备注:hd/ghs 共用 xhClear,须写清渠道。
+     */
+    public static function buildOnlineRechargeClearRemark($payWay)
+    {
+        $base = '线上充值销账';
+        $payWay = intval($payWay);
+        $wxPay = intval(dict::getDict('payWay', 'wxPay'));
+        $aliPay = intval(dict::getDict('payWay', 'alipay'));
+        if ($payWay === $wxPay) {
+            return $base . '-微信';
+        }
+        if ($payWay === $aliPay) {
+            return $base . '-支付宝';
+        }
+        $nameMap = dict::getDict('payWayName');
+        if (isset($nameMap[$payWay]) && $nameMap[$payWay] !== '') {
+            return $base . '-' . $nameMap[$payWay];
+        }
+        return $base;
+    }
+
+    /**
+     * 线上支付已入账后的 FIFO 销账(CustomRechargeClass::thirdPay)。
+     * $balanceBeforeRecharge 为本次入账前客户净余额,用于 xhClear.onlinePay 判定。
+     */
+    public static function onlinePayFifoClear($custom, $ghs, $shop, $amount, $customRecharge, $ghsRecharge = null, $balanceBeforeRecharge = null)
     {
         $pair = self::lockAccountPair($custom, $ghs);
         $pool = self::money($amount);
 
         self::voidAwaitPayClearBills($pair['custom']->id ?? 0);
 
+        $payWay = intval(is_object($customRecharge) ? ($customRecharge->payWay ?? dict::getDict('payWay', 'unPay')) : dict::getDict('payWay', 'unPay'));
+        $thirdNo = is_object($customRecharge) ? (string)($customRecharge->returnCode ?? '') : '';
+
         $allocate = self::fifoSettleWithPool($pair, $shop, null, $pool, [
-            'remark' => '线上充值销账',
+            'remark' => self::buildOnlineRechargeClearRemark($payWay),
+            'payWay' => $payWay,
+            'thirdNo' => $thirdNo,
+            'balanceBeforeRecharge' => $balanceBeforeRecharge,
             'deduct_balance' => false,
         ]);
 
@@ -225,18 +257,49 @@ class GhsRechargeSettleService
         $sjId = $shop->sjId ?? 0;
         $shopId = $shop->id ?? 0;
 
+        $payWay = isset($options['payWay']) && is_numeric($options['payWay'])
+            ? intval($options['payWay'])
+            : intval(dict::getDict('payWay', 'unPay'));
+        // 线上充值销账:仅当本次来款足额销账且入账前无正余额时标 onlinePay=yes
+        if (array_key_exists('balanceBeforeRecharge', $options)) {
+            $onlinePay = self::resolveClearOnlinePayForRechargeFifo(
+                $options['balanceBeforeRecharge'],
+                $planTotal,
+                $pool,
+                $payWay,
+                !empty($options['deduct_balance'])
+            );
+        } elseif (isset($options['onlinePay']) && is_numeric($options['onlinePay'])) {
+            $onlinePay = intval($options['onlinePay']);
+        } else {
+            $onlinePay = self::resolveOnlinePayByPayWay($payWay);
+        }
+
         $clear = OrderClearClass::clearWithAmountMap([
             'customId' => $customId,
             'ghsShopAdminId' => $staffId,
             'ghsShopId' => $shopId,
             'ghsShopAdminName' => $staffName,
             'modifyPrice' => $planTotal,
-            'payWay' => 0,
+            'payWay' => $payWay,
+            'onlinePay' => $onlinePay,
             'complete' => 0,
             'remark' => $options['remark'] ?? '充值销账',
         ], $plan, $sjId, $shopId);
 
-        OrderClearClass::applyNetBalanceClear($clear, 0, ['skipCashMoney' => true]);
+        OrderClearClass::applyNetBalanceClear($clear, $payWay, [
+            'skipCashMoney' => true,
+            'onlinePay' => $onlinePay,
+        ]);
+
+        $clearId = intval($clear->id ?? 0);
+        if ($clearId > 0 && !empty($options['thirdNo'])) {
+            $clear = OrderClearClass::getLockById($clearId);
+            if (!empty($clear) && self::modelHasAttr($clear, 'thirdNo')) {
+                $clear->thirdNo = (string)$options['thirdNo'];
+                $clear->save(false, ['thirdNo']);
+            }
+        }
 
         $settled = self::money(OrderClearClass::sumClearAmountByClearId($clear->id ?? 0));
         if (bccomp($settled, $planTotal, 2) !== 0) {
@@ -276,7 +339,7 @@ class GhsRechargeSettleService
         if (empty($custom)) {
             util::fail('没有找到客户');
         }
-        $custom = AccountMoneyClass::ensureCustomMoneyReady($custom, true);
+        AccountMoneyClass::ensureCustomMoneyReady($custom, true);
 
         $ghsId = $custom->ghsId ?? 0;
         if (empty($ghs)) {
@@ -285,10 +348,10 @@ class GhsRechargeSettleService
         if (empty($ghs)) {
             util::fail('没有找到供货商');
         }
-        $ghs = AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
+        AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
 
         if (bccomp(self::money($custom->balance), self::money($ghs->balance), 2) !== 0) {
-            util::fail('余额有问题,请联系管理员');
+            util::fail('客户与供货商余额不一致,请联系管理员');
         }
 
         return ['custom' => $custom, 'ghs' => $ghs];
@@ -431,4 +494,47 @@ class GhsRechargeSettleService
         return bcadd((string)$value, '0', 2);
     }
 
+    /** 微信/支付宝视为线上付,其余为线下(非充值销账 FIFO 场景兜底) */
+    protected static function resolveOnlinePayByPayWay($payWay)
+    {
+        $payWay = intval($payWay);
+        $wxPay = intval(dict::getDict('payWay', 'wxPay'));
+        $aliPay = intval(dict::getDict('payWay', 'alipay'));
+        if (in_array($payWay, [$wxPay, $aliPay], true)) {
+            return intval(dict::getDict('onlinePay', 'yes'));
+        }
+        return intval(dict::getDict('onlinePay', 'not'));
+    }
+
+    /**
+     * 充值 FIFO 结账单 onlinePay:完全由本次线上来款销账且入账前无正余额 → yes,否则 not。
+     * 余额结账(deduct_balance)或掺杂历史正余额时不标线上。
+     */
+    protected static function resolveClearOnlinePayForRechargeFifo($balanceBeforeRecharge, $settledAmount, $poolAmount, $payWay, $deductBalance = false)
+    {
+        if ($deductBalance) {
+            return intval(dict::getDict('onlinePay', 'not'));
+        }
+        $payWay = intval($payWay);
+        $wxPay = intval(dict::getDict('payWay', 'wxPay'));
+        $aliPay = intval(dict::getDict('payWay', 'alipay'));
+        if (!in_array($payWay, [$wxPay, $aliPay], true)) {
+            return intval(dict::getDict('onlinePay', 'not'));
+        }
+        if ($balanceBeforeRecharge === null) {
+            return self::resolveOnlinePayByPayWay($payWay);
+        }
+        $before = bcadd((string)$balanceBeforeRecharge, '0', 2);
+        $settled = bcadd((string)$settledAmount, '0', 2);
+        $pool = bcadd((string)$poolAmount, '0', 2);
+        // 入账前已有正余额:可能掺杂来源不明的历史余额,不标线上
+        if (bccomp($before, '0', 2) > 0) {
+            return intval(dict::getDict('onlinePay', 'not'));
+        }
+        if (bccomp($settled, '0', 2) <= 0 || bccomp($settled, $pool, 2) > 0) {
+            return intval(dict::getDict('onlinePay', 'not'));
+        }
+        return intval(dict::getDict('onlinePay', 'yes'));
+    }
+
 }

+ 13 - 0
biz-ghs/order/classes/OrderClearClass.php

@@ -177,6 +177,9 @@ class OrderClearClass extends BaseClass
         }
         $payWay = isset($post['payWay']) && is_numeric($post['payWay']) ? $post['payWay'] : dict::getDict('payWay', 'unPay');
         $remark = $post['remark'] ?? '';
+        $onlinePay = isset($post['onlinePay']) && is_numeric($post['onlinePay'])
+            ? intval($post['onlinePay'])
+            : intval(dict::getDict('onlinePay', 'not'));
         $clearData = [
             'prePrice' => $amount,
             'actPrice' => $modifyPrice,
@@ -202,6 +205,7 @@ class OrderClearClass extends BaseClass
             'customAddress' => $custom['address'] ?? '',
             'deadline' => $deadline,
             'payWay' => $payWay,
+            'onlinePay' => $onlinePay,
             'num' => count($ids),
             'ghsShopName' => $ghsShopName,
             'hasNoticeCustom' => 0,
@@ -270,6 +274,15 @@ class OrderClearClass extends BaseClass
         $clear->payWay = $payWay;
         $clear->payTime = date("Y-m-d H:i:s");
         $clear->status = 2;
+        // 结清时同步 onlinePay;显式传入 not(1) 时不得被微信/支付宝兜底覆盖
+        if (array_key_exists('onlinePay', $options) && is_numeric($options['onlinePay'])) {
+            $clear->onlinePay = intval($options['onlinePay']);
+        } elseif (in_array(intval($payWay), [
+            intval(dict::getDict('payWay', 'wxPay')),
+            intval(dict::getDict('payWay', 'alipay')),
+        ], true)) {
+            $clear->onlinePay = intval(dict::getDict('onlinePay', 'yes'));
+        }
         $clear->save();
 
         $clearId = $clear->id ?? 0;