فهرست منبع

Merge branch 'redesign‌-260706' into dev

ouyang 6 روز پیش
والد
کامیت
a587f46fdd

+ 25 - 13
app-hd/controllers/MainInviteController.php

@@ -6,6 +6,7 @@ namespace hd\controllers;
 
 use bizHd\shop\classes\MainInviteClass;
 use bizHd\shop\classes\MainInviteCommissionClass;
+use bizHd\shop\classes\MainInviteFlowClass;
 use common\components\util;
 use Yii;
 
@@ -67,23 +68,34 @@ class MainInviteController extends BaseController
     }
 
     /**
-     * 佣金明细分页
+     * 佣金变动明细分页(xhMainInviteFlow)
      */
     public function actionCommissionList()
     {
-        $get = Yii::$app->request->get();
-        $settleStatus = $get['settleStatus'] ?? null;
-        if ($settleStatus === '') {
-            $settleStatus = null;
-        }
-        $list = MainInviteCommissionClass::getCommissionList($this->mainId, $settleStatus);
-        $rows = $list['list'] ?? [];
-        $formatted = [];
-        foreach ($rows as $row) {
-            $formatted[] = MainInviteCommissionClass::formatCommissionListItem($row);
-        }
-        $list['list'] = $formatted;
+        $list = MainInviteFlowClass::getFlowList($this->mainId);
         util::success($list);
     }
 
+    /**
+     * 可提现佣金全额存入中央钱包余额
+     * POST:无参,按当前登录 mainId 处理
+     */
+    public function actionDepositBalance()
+    {
+        $mainId = (int) $this->mainId;
+        $shopId = (int) $this->shopId;
+        $shopName = trim((string) ($this->shop->name ?? ''));
+        try {
+            $result = MainInviteClass::depositAbleCommissionToWallet($mainId, $shopId, $shopName);
+            $invite = MainInviteClass::getByMainId($mainId);
+            $inviteData = [
+                'totalCommission' => round((float) ($invite['totalCommission'] ?? 0), 2),
+                'ableCommission' => round((float) ($invite['ableCommission'] ?? 0), 2),
+            ];
+            util::success(array_merge($result, ['invite' => $inviteData]));
+        } catch (\Exception $e) {
+            util::fail($e->getMessage());
+        }
+    }
+
 }

+ 208 - 23
biz-hd/shop/classes/MainInviteClass.php

@@ -1,12 +1,16 @@
 <?php
 /**
  * 门店邀请主数据业务
+ * 职责:邀请码、注册减免、发佣、可提现佣金存入中央钱包
  */
 
 namespace bizHd\shop\classes;
 
 use bizHd\base\classes\BaseClass;
 use bizHd\shop\classes\MainInviteCommissionClass;
+use bizHd\shop\classes\MainInviteFlowClass;
+use bizHd\shop\classes\MainWalletChangeClass;
+use bizHd\shop\classes\MainClass;
 use common\components\dict;
 use Yii;
 
@@ -203,33 +207,214 @@ class MainInviteClass extends BaseClass
             return;
         }
 
+        $inviteId = (int) ($inviter['id'] ?? 0);
+        if ($inviteId <= 0) {
+            return;
+        }
+
         $applyId = (int) ($apply['id'] ?? 0);
         $commissionSn = 'FY' . date('YmdHis') . $applyId;
+        $flowTime = date('Y-m-d H:i:s');
+        $lsShopId = (int) ($apply['shopId'] ?? 0);
+        $lsShopName = trim((string) ($apply['name'] ?? ''));
+        $inviteeShopName = trim((string) $inviteeShopName);
+        $inviteeMobile = trim((string) $inviteeMobile);
+        $memberPayAmount = round((float) ($actPrice ?? 0), 2);
+        $prePriceAmount = round((float) ($prePrice ?? 0), 2);
 
-        MainInviteCommissionClass::add([
-            'commissionSn' => $commissionSn,
-            'inviterMainId' => $inviterMainId,
-            'lsShopId' => (int) ($apply['shopId'] ?? 0),
-            'lsShopName' => trim((string) ($apply['name'] ?? '')),
-            'inviteeMainId' => (int) $inviteeMainId,
-            'inviteeShopName' => trim((string) $inviteeShopName),
-            'inviteeMobile' => trim((string) $inviteeMobile),
-            'inviteCode' => trim((string) ($apply['inviteCode'] ?? '')),
-            'memberTypeName' => '年度会员',
-            'amount' => round((float) ($prePrice ?? 0), 2),
-            'memberPayAmount' => round((float) ($actPrice ?? 0), 2),
-            'commissionAmount' => $commissionAmount,
-            'hdDiscountAmount' => round((float) ($apply['hdDiscountAmount'] ?? 0), 2),
-            'settleStatus' => 0,
-            'payTime' => date('Y-m-d H:i:s'),
-        ], false);
+        $transaction = Yii::$app->db->beginTransaction();
+        try {
+            $inviteRow = self::getLockById($inviteId);
+            if (empty($inviteRow) || (int) ($inviteRow->mainId ?? 0) !== $inviterMainId) {
+                throw new \Exception('邀请账户无效');
+            }
+
+            $beforeAble = round((float) ($inviteRow->ableCommission ?? 0), 2);
+
+            // 1. 邀约记录(受邀花店维度)
+            $commissionLog = MainInviteCommissionClass::add([
+                'commissionSn' => $commissionSn,
+                'inviterMainId' => $inviterMainId,
+                'lsShopId' => $lsShopId,
+                'lsShopName' => $lsShopName,
+                'inviteeMainId' => (int) $inviteeMainId,
+                'inviteeShopName' => $inviteeShopName,
+                'inviteeMobile' => $inviteeMobile,
+                'inviteCode' => trim((string) ($apply['inviteCode'] ?? '')),
+                'memberTypeName' => '年度会员',
+                'amount' => $prePriceAmount,
+                'memberPayAmount' => $memberPayAmount,
+                'commissionAmount' => $commissionAmount,
+                'hdDiscountAmount' => round((float) ($apply['hdDiscountAmount'] ?? 0), 2),
+                'settleStatus' => 0,
+                'payTime' => $flowTime,
+            ], true);
+            $commissionId = (int) ($commissionLog->id ?? 0);
+
+            // 2. 累加 inviteCount / totalCommission / ableCommission
+            $inviteCount = (int) ($inviteRow->inviteCount ?? 0) + 1;
+            $totalCommission = round((float) ($inviteRow->totalCommission ?? 0) + $commissionAmount, 2);
+            $ableCommission = round($beforeAble + $commissionAmount, 2);
+            self::updateById($inviteId, [
+                'inviteCount' => $inviteCount,
+                'totalCommission' => $totalCommission,
+                'ableCommission' => $ableCommission,
+            ]);
+
+            // 3. 佣金变动流水(+获佣)
+            MainInviteFlowClass::add([
+                'mainId' => $inviterMainId,
+                'flowType' => MainInviteFlowClass::FLOW_TYPE_EARN,
+                'amount' => $commissionAmount,
+                'ableAfter' => $ableCommission,
+                'refType' => MainInviteFlowClass::REF_TYPE_COMMISSION,
+                'refId' => $commissionId,
+                'refSn' => $commissionSn,
+                'inviteeShopName' => $inviteeShopName !== '' ? $inviteeShopName : $lsShopName,
+                'inviteeMobile' => $inviteeMobile,
+                'lsShopId' => $lsShopId,
+                'baseAmount' => $memberPayAmount > 0 ? $memberPayAmount : $prePriceAmount,
+                'flowTime' => $flowTime,
+                'remark' => '邀请开通获佣',
+            ], true);
+
+            $transaction->commit();
+        } catch (\Throwable $e) {
+            $transaction->rollBack();
+            throw $e;
+        }
+    }
+
+    /**
+     * 将全部可提现佣金存入 xhMain.walletBalance(全额存入,非部分)
+     *
+     * @param int $mainId 邀请人中央 id
+     * @param int $shopId 当前门店 id(写佣金流水快照)
+     * @param string $shopName 门店名称快照
+     * @return array commissionSn、depositAmount、ableCommission、walletBalance
+     * @throws \Throwable
+     */
+    public static function depositAbleCommissionToWallet($mainId, $shopId, $shopName = '')
+    {
+        $mainId = (int) $mainId;
+        $shopId = (int) $shopId;
+        if ($mainId <= 0) {
+            throw new \Exception('账户无效');
+        }
+
+        $lockKey = 'main_invite_deposit_' . $mainId;
+        $locked = Yii::$app->redis->executeCommand('SET', [$lockKey, '1', 'NX', 'EX', 15]);
+        if ($locked === false || $locked === null) {
+            throw new \Exception('操作进行中,请稍后再试');
+        }
 
-        $inviteCount = (int) ($inviter['inviteCount'] ?? 0) + 1;
-        $totalCommission = round((float) ($inviter['totalCommission'] ?? 0) + $commissionAmount, 2);
-        self::updateById((int) $inviter['id'], [
-            'inviteCount' => $inviteCount,
-            'totalCommission' => $totalCommission,
-        ]);
+        try {
+            return self::depositAbleCommissionToWalletInTransaction($mainId, $shopId, trim((string) $shopName));
+        } finally {
+            Yii::$app->redis->executeCommand('DEL', [$lockKey]);
+        }
+    }
+
+    /**
+     * 事务内:扣减 ableCommission、写佣金存入流水、增加钱包余额并记 xhMainWalletChange
+     */
+    protected static function depositAbleCommissionToWalletInTransaction($mainId, $shopId, $shopName)
+    {
+        $preview = self::getByMainId($mainId);
+        if (empty($preview)) {
+            throw new \Exception('暂无邀请账户');
+        }
+        $inviteId = (int) ($preview['id'] ?? 0);
+        if ($inviteId <= 0) {
+            throw new \Exception('暂无邀请账户');
+        }
+
+        $transaction = Yii::$app->db->beginTransaction();
+        try {
+            $invite = self::getLockById($inviteId);
+            if (empty($invite) || (int) ($invite->mainId ?? 0) !== $mainId) {
+                throw new \Exception('邀请账户无效');
+            }
+
+            $beforeAble = round((float) ($invite->ableCommission ?? 0), 2);
+            if ($beforeAble <= 0) {
+                throw new \Exception('暂无可存入佣金');
+            }
+            $amount = $beforeAble;
+            $afterAble = 0;
+
+            $main = MainClass::getLockById($mainId);
+            if (empty($main)) {
+                throw new \Exception('账户无效');
+            }
+
+            $flowTime = date('Y-m-d H:i:s');
+            $depositSn = 'CR' . date('YmdHis') . $mainId;
+
+            // 1. 扣减可提现佣金(累计 totalCommission 不变)
+            self::updateById($inviteId, ['ableCommission' => $afterAble]);
+
+            // 2. 中央钱包余额增加
+            $beforeWallet = round((float) ($main->walletBalance ?? 0), 2);
+            $afterWallet = round($beforeWallet + $amount, 2);
+            MainClass::updateById($mainId, ['walletBalance' => $afterWallet]);
+
+            // 3. 钱包变动流水
+            $capitalType = dict::getDict('capitalType', 'inviteCommissionDeposit', 'id');
+            $payWay = dict::getDict('payWay', 'unknown');
+            $ptStyle = dict::getDict('ptStyle', 'hd');
+            $fromType = dict::getDict('fromType', 'shop');
+            $ioIncome = dict::getDict('io', 'income');
+
+            $walletChange = MainWalletChangeClass::add([
+                'relateId' => 0,
+                'ptStyle' => $ptStyle,
+                'capitalType' => $capitalType,
+                'amount' => $amount,
+                'balance' => $afterWallet,
+                'io' => $ioIncome,
+                'payWay' => $payWay,
+                'fromType' => $fromType,
+                'event' => '佣金存入余额' . $depositSn,
+                'mainId' => $mainId,
+                'remark' => '邀请佣金存入中央钱包',
+            ], true);
+            $walletChangeId = (int) ($walletChange->id ?? 0);
+
+            // 4. 佣金变动流水(-存入,同步 ableAfter)
+            $flowLog = MainInviteFlowClass::add([
+                'mainId' => $mainId,
+                'flowType' => MainInviteFlowClass::FLOW_TYPE_DEPOSIT,
+                'amount' => round(0 - $amount, 2),
+                'ableAfter' => $afterAble,
+                'refType' => MainInviteFlowClass::REF_TYPE_WALLET_CHANGE,
+                'refId' => $walletChangeId,
+                'refSn' => $depositSn,
+                'inviteeShopName' => $shopName,
+                'inviteeMobile' => '',
+                'lsShopId' => $shopId,
+                'baseAmount' => $amount,
+                'flowTime' => $flowTime,
+                'remark' => '佣金存入余额',
+            ], true);
+            $flowId = (int) ($flowLog->id ?? 0);
+
+            if ($walletChangeId > 0 && $flowId > 0) {
+                MainWalletChangeClass::updateById($walletChangeId, ['relateId' => $flowId]);
+            }
+
+            $transaction->commit();
+
+            return [
+                'commissionSn' => $depositSn,
+                'depositAmount' => $amount,
+                'ableCommission' => $afterAble,
+                'walletBalance' => $afterWallet,
+            ];
+        } catch (\Throwable $e) {
+            $transaction->rollBack();
+            throw $e;
+        }
     }
 
 }

+ 10 - 2
biz-hd/shop/classes/MainInviteCommissionClass.php

@@ -37,6 +37,7 @@ class MainInviteCommissionClass extends BaseClass
         }
         return self::getLimitList('*', [
             'inviterMainId' => (int) $inviterMainId,
+            'inviteeMainId>' => 0,
         ], (int) $limit, 'addTime DESC,id DESC');
     }
 
@@ -87,8 +88,12 @@ class MainInviteCommissionClass extends BaseClass
         }
 
         $keyword = trim((string) $keyword);
+        $baseWhere = [
+            'inviterMainId' => $mainId,
+            'inviteeMainId>' => 0,
+        ];
         if ($keyword === '') {
-            $result = self::getList('*', ['inviterMainId' => $mainId], 'addTime DESC,id DESC');
+            $result = self::getList('*', $baseWhere, 'addTime DESC,id DESC');
         } else {
             // 店名 / 冗余字段 inviteeMobile 模糊匹配
             $result = self::getInviteShopListByKeyword($mainId, $keyword);
@@ -114,7 +119,10 @@ class MainInviteCommissionClass extends BaseClass
             : (int) (Yii::$app->params['pageSize'] ?? 20);
 
         $model = self::getModel();
-        $query = $model->conditionQuery(['inviterMainId' => (int) $inviterMainId]);
+        $query = $model->conditionQuery([
+            'inviterMainId' => (int) $inviterMainId,
+            'inviteeMainId>' => 0,
+        ]);
         $query->andWhere([
             'or',
             ['like', 'inviteeShopName', $keyword],

+ 140 - 0
biz-hd/shop/classes/MainInviteFlowClass.php

@@ -0,0 +1,140 @@
+<?php
+/**
+ * 邀请佣金变动流水 xhMainInviteFlow
+ * 职责:佣金变动明细分页、格式化;配合 xhMainInvite.ableCommission 落 ableAfter 快照
+ */
+namespace bizHd\shop\classes;
+
+use biz\shop\classes\ShopClass;
+use bizHd\base\classes\BaseClass;
+use common\components\dateUtil;
+use Yii;
+
+class MainInviteFlowClass extends BaseClass
+{
+
+    public static $baseFile = '\bizHd\shop\models\MainInviteFlow';
+
+    /** 邀请开通获佣 */
+    const FLOW_TYPE_EARN = 1;
+
+    /** 佣金存入中央钱包 */
+    const FLOW_TYPE_DEPOSIT = 2;
+
+    /** 退款扣回佣金 */
+    const FLOW_TYPE_REFUND = 3;
+
+    /** 关联 xhMainInviteCommission.id */
+    const REF_TYPE_COMMISSION = 1;
+
+    /** 关联 xhMainWalletChange.id */
+    const REF_TYPE_WALLET_CHANGE = 2;
+
+    /**
+     * 佣金变动明细分页(默认近30天)
+     */
+    public static function getFlowList($mainId)
+    {
+        $where = self::buildFlowListWhere($mainId);
+        $result = self::getList('*', $where, 'flowTime DESC,id DESC');
+        $rows = $result['list'] ?? [];
+        $list = [];
+        foreach ($rows as $row) {
+            $list[] = self::formatFlowListItem($row);
+        }
+        $result['list'] = $list;
+        return $result;
+    }
+
+    /**
+     * 列表查询条件:mainId + 时间筛选
+     */
+    protected static function buildFlowListWhere($mainId)
+    {
+        $where = ['mainId' => (int) $mainId];
+        $get = Yii::$app->request->get();
+        $searchTime = isset($get['searchTime']) ? trim((string) $get['searchTime']) : 'last30Days';
+        $startTime = isset($get['startTime']) ? trim((string) $get['startTime']) : '';
+        $endTime = isset($get['endTime']) ? trim((string) $get['endTime']) : '';
+        if ($searchTime !== '' && $searchTime !== 'all') {
+            $period = dateUtil::formatTime($searchTime, $startTime, $endTime);
+            if (!empty($period['startTime']) && !empty($period['endTime'])) {
+                $where['flowTime'] = ['between', [$period['startTime'], $period['endTime']]];
+            }
+        }
+        return $where;
+    }
+
+    /**
+     * 格式化单行,字段与 hdApp shopInviteCommissionList 一致
+     */
+    public static function formatFlowListItem($row)
+    {
+        $flowType = (int) ($row['flowType'] ?? 0);
+        $lsShopId = (int) ($row['lsShopId'] ?? 0);
+        $shop = [];
+        if ($lsShopId > 0) {
+            $shop = ShopClass::getById($lsShopId, false) ?: [];
+        }
+
+        $shopName = trim((string) ($row['inviteeShopName'] ?? ''));
+        $mobile = trim((string) ($row['inviteeMobile'] ?? ''));
+        $mobileMask = $mobile !== '' ? MainInviteCommissionClass::maskMobile($mobile) : '-';
+
+        if ($flowType === self::FLOW_TYPE_DEPOSIT) {
+            $orderSnLabel = '存入编号';
+            $baseAmountLabel = '存余额金额';
+            $recordType = 'deposit';
+        } else {
+            $orderSnLabel = '会员订单号';
+            $baseAmountLabel = '会员实付金额';
+            $recordType = 'member';
+        }
+
+        $orderSn = trim((string) ($row['refSn'] ?? ''));
+        $baseAmount = round((float) ($row['baseAmount'] ?? 0), 2);
+        $rawAmount = round((float) ($row['amount'] ?? 0), 2);
+        $commissionAmount = round(abs($rawAmount), 2);
+        $commissionSign = $rawAmount < 0 ? -1 : 1;
+        if ($flowType === self::FLOW_TYPE_REFUND) {
+            $commissionSign = -1;
+        }
+
+        $createTime = trim((string) ($row['flowTime'] ?? ($row['addTime'] ?? '')));
+        if ($createTime !== '' && strlen($createTime) === 10) {
+            $createTime .= ' 00:00:00';
+        }
+
+        return [
+            'id' => $row['id'] ?? 0,
+            'shopName' => $shopName !== '' ? $shopName : '-',
+            'shopImg' => self::resolveShopImg($shop),
+            'mobile' => $mobile !== '' ? $mobile : '-',
+            'mobileMask' => $mobileMask,
+            'orderSnLabel' => $orderSnLabel,
+            'orderSn' => $orderSn !== '' ? $orderSn : '-',
+            'baseAmountLabel' => $baseAmountLabel,
+            'baseAmount' => $baseAmount,
+            'createTime' => $createTime !== '' ? $createTime : '-',
+            'commissionAmount' => $commissionAmount,
+            'commissionSign' => $commissionSign,
+            'recordType' => $recordType,
+            'flowType' => $flowType,
+            'ableAfter' => round((float) ($row['ableAfter'] ?? 0), 2),
+        ];
+    }
+
+    protected static function resolveShopImg($shop)
+    {
+        $avatar = is_array($shop) ? ($shop['avatar'] ?? '') : '';
+        if (empty($avatar)) {
+            return '';
+        }
+        if (strpos($avatar, 'http') === 0) {
+            return $avatar;
+        }
+        $host = Yii::$app->params['hdImgHost'] ?? '';
+        return $host . $avatar;
+    }
+
+}

+ 18 - 0
biz-hd/shop/models/MainInviteFlow.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * 邀请佣金变动流水 xhMainInviteFlow
+ * 用途:hdApp 佣金变动明细;与 xhMainInviteCommission(邀约记录)分离
+ */
+namespace bizHd\shop\models;
+
+use bizHd\base\models\Base;
+
+class MainInviteFlow extends Base
+{
+
+    public static function tableName()
+    {
+        return 'xhMainInviteFlow';
+    }
+
+}

+ 13 - 8
biz/renew/classes/RenewClass.php

@@ -129,14 +129,19 @@ class RenewClass extends BaseClass
         if ($isRegisterMember && !self::hasOtherPaidMemberRenew((int) $mainId, (string) $orderSn)) {
             $apply = ApplyClass::getById($applyId);
             if (!empty($apply)) {
-                MainInviteClass::grantInviterCommission(
-                    $apply,
-                    (int) $mainId,
-                    trim((string) ($apply['name'] ?? '')),
-                    trim((string) ($apply['mobile'] ?? '')),
-                    round((float) ($renew->prePrice ?? 0), 2),
-                    round((float) ($renew->actPrice ?? 0), 2)
-                );
+                try {
+                    MainInviteClass::grantInviterCommission(
+                        $apply,
+                        (int) $mainId,
+                        trim((string) ($apply['name'] ?? '')),
+                        trim((string) ($apply['mobile'] ?? '')),
+                        round((float) ($renew->prePrice ?? 0), 2),
+                        round((float) ($renew->actPrice ?? 0), 2)
+                    );
+                } catch (\Throwable $e) {
+                    $msg = '邀请发佣失败 orderSn:' . $orderSn . ' ' . $e->getMessage();
+                    noticeUtil::push($msg, '15280215347');
+                }
             }
         }
 

+ 2 - 0
common/components/dict.php

@@ -513,6 +513,8 @@ class dict
             'distributionDeposit' => ['id' => 83, 'name' => 'distributionDeposit'],
             // 花店注册年度会员支付
             'hdRegisterOrder' => ['id' => 84, 'name' => 'hdRegisterOrder'],
+            // 邀请佣金存入中央钱包(xhMainInviteFlow + xhMainWalletChange)
+            'inviteCommissionDeposit' => ['id' => 85, 'name' => 'inviteCommissionDeposit'],
         ],
         "capitalTypeList" => [//流水类型的对应链接,后台收支明细查看时跳转的链接
             0 => ['link' => '/capital/order-detail', 'name' => '网店', 'orderLink' => '/order/detail', 'id' => 0,],