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

Merge branch 'clear-cg' into dev

shish 2 месяцев назад
Родитель
Сommit
31876f4be3

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

@@ -7,6 +7,7 @@ use biz\common\classes\GhsNotifyClass;
 use biz\ghs\classes\GhsClass;
 use biz\shop\classes\ShopClass;
 use biz\shop\classes\ShopExtClass;
+use bizGhs\custom\classes\AccountMoneyClass;
 use bizGhs\custom\classes\CustomClass;
 use bizGhs\express\classes\GhsDeliveryOrderClass;
 use bizGhs\order\classes\OrderClass;
@@ -976,6 +977,102 @@ class PurchaseController extends BaseController
         util::success($info->attributes);
     }
 
+    /**
+     * 采购待支付页:客户 xhGhsCustom 净余额支付(并发重试 + 行锁)。
+     */
+    public function actionCustomBalancePay()
+    {
+        $post = Yii::$app->request->post();
+        $orderSn = $post['orderSn'] ?? '';
+        if (empty($orderSn)) {
+            util::fail('订单号无效');
+        }
+
+        $cacheKey = 'hd_custom_balance_pay_' . $orderSn;
+        $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
+        if (!empty($has)) {
+            util::fail('请稍等...');
+        }
+        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 6, 'has']);
+
+        $info = PurchaseClass::getByCondition(['orderSn' => $orderSn], true);
+        if (empty($info)) {
+            util::fail('没有找到采购单');
+        }
+        PurchaseService::valid($info, $this->shopId);
+
+        $deadline = $info->deadline ?? '';
+        if (!empty($deadline) && time() > strtotime($deadline)) {
+            util::fail('订单已失效了哦');
+        }
+
+        $ghsId = intval($info->ghsId ?? 0);
+        $ghs = GhsClass::getGhsInfo($ghsId);
+
+        try {
+            $result = util::runWithDbConcurrencyRetry(function () use ($orderSn) {
+                $connection = Yii::$app->db;
+                $transaction = $connection->beginTransaction();
+                try {
+                    $purchase = PurchaseClass::getByCondition(['orderSn' => $orderSn], true);
+                    $respond = PurchaseService::payByGhsCustomBalance($purchase);
+                    $transaction->commit();
+                    return $respond;
+                } catch (\Exception $exception) {
+                    if ($transaction->isActive) {
+                        $transaction->rollBack();
+                    }
+                    throw $exception;
+                }
+            });
+
+            $info = $result['purchase'];
+            $order = $result['saleOrder'] ?? null;
+
+            if (!empty($order)) {
+                if (isset($info->book) && $info->book == 0 && !empty($ghs)) {
+                    $ghsShopId = $ghs['shopId'] ?? 0;
+                    $ext = ShopExtClass::getByCondition(['shopId' => $ghsShopId], true, null, 'id,shopId,orderFlow');
+                    if (!empty($ext) && intval($ext->orderFlow ?? 0) === 0) {
+                        $cg = PurchaseClass::getByCondition(['orderSn' => $orderSn], true);
+                        if (!empty($cg)) {
+                            PurchaseClass::confirmTake($cg);
+                        }
+                    }
+                }
+
+                $shopId = $order->shopId ?? 0;
+                $shop = ShopClass::getById($shopId, true);
+                if (!empty($shop)) {
+                    GhsNotifyClass::newOrderNotify($order->id ?? 0);
+                }
+                if (isset($order->needPrint) && $order->needPrint == dict::getDict('needPrint', 'need')) {
+                    OrderClass::onlinePrint($order);
+                }
+                GhsDeliveryOrderClass::payAfter($order);
+
+                $customId = $order->customId ?? 0;
+                $custom = CustomClass::getById($customId, true);
+                $date = date('Y-m-d H:i:s');
+                if (!empty($custom)) {
+                    $custom->recentExpend = $date;
+                    $custom->save();
+                }
+                $orderGhsId = $order->ghsId ?? 0;
+                $orderGhs = GhsClass::getById($orderGhsId, true);
+                if (!empty($orderGhs)) {
+                    $orderGhs->recentExpend = $date;
+                    $orderGhs->save();
+                }
+            }
+
+            util::success($info->attributes);
+        } catch (\Exception $e) {
+            Yii::info('客户余额支付失败:' . $e->getMessage());
+            util::fail($e->getMessage() ?: '支付失败');
+        }
+    }
+
     //余额支付 ssh 2021.1.24
     public function actionBalancePay()
     {
@@ -1008,8 +1105,8 @@ class PurchaseController extends BaseController
         $connection = Yii::$app->db;
         $transaction = $connection->beginTransaction();
         try {
-            //余额支付
-            purchaseService::balancePay($info);
+            // 余额支付:走 xhGhsCustom,不扣 main.balance
+            $info = PurchaseService::balancePay($info);
             $transaction->commit();
         } catch (\Exception $e) {
             $transaction->rollBack();
@@ -1135,7 +1232,30 @@ class PurchaseController extends BaseController
         $shop = $this->shop;
         $info['pfShopId'] = $shop->pfShopId ?? 0;
         $info['hasDebtPay'] = $hasDebtPay;
-        $info['balance'] = $shop->balance ?? 0;
+        // 待支付页展示 xhGhsCustom 净余额(正数=可支付余额),不再使用 main.balance
+        $info['balance'] = 0;
+        $info['customNetBalance'] = '0.00';
+        $info['showBalancePay'] = 0;
+        $info['ghsSalt'] = '';
+        $ghsId = intval($info['ghsId'] ?? 0);
+        if ($ghsId > 0) {
+            $ghsRow = GhsClass::getById($ghsId, true);
+            if (!empty($ghsRow)) {
+                $info['ghsSalt'] = $ghsRow->salt ?? '';
+                $ghsCustomId = intval($ghsRow->customId ?? 0);
+                if ($ghsCustomId > 0) {
+                    $ghsCustom = CustomClass::getById($ghsCustomId, true);
+                    if (!empty($ghsCustom)) {
+                        $net = AccountMoneyClass::getNetBalanceFromRow($ghsCustom);
+                        $info['customNetBalance'] = $net;
+                        if (bccomp($net, '0', 2) > 0) {
+                            $info['balance'] = floatval($net);
+                            $info['showBalancePay'] = 1;
+                        }
+                    }
+                }
+            }
+        }
         $getPayType = dict::getDict('getPayType');
         $info['getPayType'] = $getPayType;
 

+ 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('余额有问题,请向客服反应');
         }
     }
 

+ 3 - 3
biz-ghs/custom/services/GhsRechargeSettleService.php

@@ -276,7 +276,7 @@ class GhsRechargeSettleService
         if (empty($custom)) {
             util::fail('没有找到客户');
         }
-        AccountMoneyClass::ensureCustomMoneyReady($custom, true);
+        $custom = AccountMoneyClass::ensureCustomMoneyReady($custom, true);
 
         $ghsId = $custom->ghsId ?? 0;
         if (empty($ghs)) {
@@ -285,10 +285,10 @@ class GhsRechargeSettleService
         if (empty($ghs)) {
             util::fail('没有找到供货商');
         }
-        AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
+        $ghs = 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];

+ 2 - 2
biz-ghs/order/classes/OrderClass.php

@@ -3083,8 +3083,8 @@ XL;
                 return false;
             }
         }
-        //东莞我要花 福州福清我要花 手机后四号变星号
-        if (in_array((int)$orderMainId, [25119, 2644,10652,2084,89473], true)) {
+        //东莞我要花 手机后四号变星号
+        if (in_array((int)$orderMainId, [2644,10652,2084,89473], true)) {
             $customMobile = preg_replace('/(.{4})$/u', '****', trim($customMobile));
         }
         $customName = $order->customName ?? '';

+ 74 - 34
biz-hd/purchase/services/PurchaseService.php

@@ -9,7 +9,9 @@ use biz\shop\classes\ShopCouponClass;
 use biz\stat\classes\StatCgClass;
 use biz\stat\classes\StatCgGhsClass;
 use biz\stat\classes\StatOutClass;
+use bizGhs\custom\classes\AccountMoneyClass;
 use bizGhs\custom\classes\CustomClass;
+use bizGhs\custom\services\GhsRechargeSettleService;
 use bizGhs\order\classes\OrderClass;
 use bizGhs\order\services\OrderService;
 use bizHd\base\services\BaseService;
@@ -349,15 +351,81 @@ class PurchaseService extends BaseService
 
     }
 
-    //余额支付 ssh 2021.1.24
+    /**
+     * 采购单余额支付(超管密码入口等)。
+     * 批发-客户资金只在 xhGhs / xhGhsCustom,不扣 xhShop / xhMain.balance。
+     */
     public static function balancePay($info)
     {
+        $result = self::payByGhsCustomBalance($info);
+        return $result['purchase'] ?? $info;
+    }
+
+    /**
+     * 花店采购余额付:批发商-客户资金只在 xhGhs/xhGhsCustom,先销售单 payAfter 扣净余额,再采购单 payAfter 改状态。
+     * xhShop/xhMain 仅为花店门店属性,不参与本关系余额扣减。须在事务内调用;并发由外层重试 + 行锁保证。
+     */
+    public static function payByGhsCustomBalance($purchase)
+    {
+        if (empty($purchase)) {
+            util::fail('没有找到采购单');
+        }
+        if (intval($purchase->status ?? 0) == PurchaseClass::STATUS_CANCEL) {
+            util::fail('订单已取消');
+        }
+        if (intval($purchase->status ?? 0) != PurchaseClass::STATUS_UN_PAY) {
+            util::fail('订单不是待付款状态');
+        }
+        if (intval($purchase->payStatus ?? 0) === 1) {
+            util::fail('订单已经付过款了');
+        }
+        $saleId = intval($purchase->saleId ?? 0);
+        if ($saleId <= 0) {
+            util::fail('订单无法余额支付');
+        }
+
+        $purchaseId = intval($purchase->id ?? 0);
+        $purchase = PurchaseClass::getLockById($purchaseId);
+        $order = OrderClass::getLockById($saleId);
+        if (empty($order)) {
+            util::fail('没有找到销售单');
+        }
+        if (intval($order->status ?? 0) != OrderClass::ORDER_STATUS_UN_PAY) {
+            util::fail('重复操作');
+        }
+
+        $customId = intval($order->customId ?? 0);
+        $pair = GhsRechargeSettleService::lockAccountPair(['id' => $customId]);
+        $custom = $pair['custom'];
+        if (empty($custom)) {
+            util::fail('没有找到客户信息');
+        }
+        AccountMoneyClass::ensureCustomMoneyReady($custom, true);
+        // 与待支付页 realPrice 一致,避免 actPrice 与 realPrice 不一致时误报余额不足
+        $payAmount = bcadd((string)($purchase->realPrice ?? $order->realPrice ?? $order->actPrice ?? '0'), '0', 2);
+        $beforeBalance = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        if (bccomp($beforeBalance, $payAmount, 2) < 0) {
+            util::fail('余额不足');
+        }
+
         $payWay = dict::getDict('payWay', 'balancePay');
-        self::payAfter($info, $payWay);
+        OrderService::payAfter($order, $payWay, false);
 
-        $saleId = $info->saleId ?? 0;
-        $order = OrderClass::getById($saleId, true);
-        OrderService::payAfter($order, $payWay, true);
+        $purchase = PurchaseClass::getLockById($purchaseId);
+        $saleOrder = OrderClass::getById($saleId, true);
+        if (!empty($purchase) && !empty($saleOrder) && intval($saleOrder->payStatus ?? 0) === 1) {
+            $purchase->remainDebtPrice = $saleOrder->remainDebtPrice ?? '0.00';
+            $purchase->debtPrice = $saleOrder->debtPrice ?? '0.00';
+            $purchase->debt = ($saleOrder->debt ?? 0) == OrderClass::DEBT_YES
+                ? PurchaseClass::DEBT_YES : PurchaseClass::DEBT_NO;
+            $purchase->save(false, ['remainDebtPrice', 'debtPrice', 'debt']);
+        }
+        self::payAfter($purchase, $payWay);
+
+        return [
+            'purchase' => $purchase,
+            'saleOrder' => OrderClass::getById($saleId, true),
+        ];
     }
 
     //付款码支付处理流程 ssh 20211231
@@ -457,31 +525,6 @@ class PurchaseService extends BaseService
 
     }
 
-    /**
-     * 采购单余额付是否扣减花店 main.balance。
-     * main.balance 已废弃、后续会删,批发余额以 xhGhsCustom 净余额为准(OrderService::payToChangeBalance)。
-     * 仅「花店自助采购、先付采购单」等遗留路径仍可能走 purchaseReduceBalance,待 main.balance 下线后一并改。
-     */
-    protected static function shouldReduceMainBalanceOnBalancePay($info)
-    {
-        if (intval($info->cgStyle ?? 0) !== intval(dict::getDict('cgStyle', 'ghs'))) {
-            return true;
-        }
-        $saleId = intval($info->saleId ?? 0);
-        if ($saleId <= 0) {
-            return true;
-        }
-        $saleOrder = OrderClass::getById($saleId, true);
-        if (empty($saleOrder) || intval($saleOrder->payStatus ?? 0) !== 1) {
-            return true;
-        }
-        // 批发开单先完成销售单 payAfter:客户余额已扣,勿再动 main.balance
-        if (intval($saleOrder->payWay ?? -1) === intval(dict::getDict('payWay', 'balancePay'))) {
-            return false;
-        }
-        return true;
-    }
-
     //第三方支付、余额支付和欠款支付后调用的流程 ssh 2021.4.27
     public static function payAfter($info, $payWay)
     {
@@ -563,10 +606,7 @@ class PurchaseService extends BaseService
         }
         $realPrice = $info->realPrice;
         $actPrice = $info->actPrice;
-        // 余额支付:批发开单只扣 xhGhsCustom;main.balance 已废弃,见 shouldReduceMainBalanceOnBalancePay
-        if ($payWay == dict::getDict('payWay', 'balancePay') && self::shouldReduceMainBalanceOnBalancePay($info)) {
-            ShopClass::purchaseReduceBalance($main, $shop, $realPrice, $info);
-        }
+        // 余额支付:批发商-客户资金在 xhGhs/xhGhsCustom(销售单 payAfter 扣款),不扣 xhMain.balance
         $main->totalPurchase = bcadd($main->totalPurchase, $actPrice, 2);
         $currentExpend = bcadd($main->totalExpend, $actPrice, 2);
         $main->totalExpend = $currentExpend;

+ 1 - 1
common/components/delivery/services/DispatchService.php

@@ -1099,7 +1099,7 @@ class DispatchService
         foreach ($priceConditions as $condition) {
             $couponId = $condition['coupon_info']['coupon_id'] ?? null;
             if (!empty($couponId)) {
-                return $couponId;
+                return (string)$couponId; //转换为字符串,以免在传递过程中丢失精度(包括传递给前端时)
             }
         }
 

+ 9 - 4
common/components/delivery/services/adapter/HuolalaAdapter.php

@@ -102,7 +102,7 @@ class HuolalaAdapter extends Huolala implements Adapter
             'order_vehicle_id' => $params['order_vehicle_id'],
             'addr_info' => $addrInfo,
             'vehicle_std' => $params['vehicle_std'] ?? [],
-            //'spec_req' => $params['spec_req'], // 跑腿车型,传这个值会出现"核价失败"
+            'spec_req' => $params['spec_req'],
             'order_time' => (int)$orderTime,
             'contact_name' => $shop['merchantName'],
             'contact_phone_no' => $shop['mobile'],
@@ -124,6 +124,11 @@ class HuolalaAdapter extends Huolala implements Adapter
         // 添加订单消息回调地址
         $apiData['notify_url'] = $this->notifyUrl;
 
+        // 跑腿车型,传这个值会出现"核价失败",所以要去除
+        if ($params['type'] == '跑腿') {
+            unset($apiData['spec_req']);
+        }
+
         return $apiData;
     }
 
@@ -179,7 +184,7 @@ class HuolalaAdapter extends Huolala implements Adapter
             $apiData['vehicle_std'] = is_array($order['vehicle_std']) ? $order['vehicle_std'] : [$order['vehicle_std']];
         }
         if (!empty($order['spec_req']) && is_array($order['spec_req'])) {
-            //$apiData['spec_req'] = array_map('intval', $order['spec_req']); // 跑腿车型,传这个值会出现"核价失败"
+            $apiData['spec_req'] = array_map('intval', $order['spec_req']);
         }
         if (!empty($order['remark'])) {
             $apiData['remark'] = $order['remark'];
@@ -194,7 +199,7 @@ class HuolalaAdapter extends Huolala implements Adapter
             $apiData['notify_url'] = $order['notify_url'];
         }
         if (isset($order['coupon_id'])) {
-            $apiData['coupon_id'] = $order['coupon_id'];
+            $apiData['coupon_id'] = intval($order['coupon_id']);
         }
         if (isset($order['invoice_type'])) {
             $apiData['invoice_type'] = (int)$order['invoice_type'];
@@ -378,7 +383,7 @@ class HuolalaAdapter extends Huolala implements Adapter
                 $apiData['vehicle_std'] = is_array($vehicle['vehicle_std']) ? $vehicle['vehicle_std'] : [$vehicle['vehicle_std']];
             }
             if (!empty($vehicle['spec_req'])) {
-                //$apiData['spec_req'] = is_array($vehicle['spec_req']) ? $vehicle['spec_req'] : [$vehicle['spec_req']]; // 跑腿车型,传这个值会出现"核价失败" -- 统一不传试试
+                $apiData['spec_req'] = is_array($vehicle['spec_req']) ? $vehicle['spec_req'] : [$vehicle['spec_req']];
             }
             if (isset($vehicle['coupon_id']) && !empty($vehicle['coupon_id'])) {
                 $apiData['coupon_id'] = $vehicle['coupon_id'];