|
|
@@ -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;
|
|
|
|
|
|
@@ -26,6 +30,34 @@ class MainInviteClass extends BaseClass
|
|
|
return self::getByCondition(['mainId' => (int)$mainId], false);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 确保 xhMainInvite 存在(邀请人账户);无记录则按 dict 默认规则自动初始化
|
|
|
+ * 供 shopInviteHub 首页、生成邀请码等入口调用;并发下 uk_mainId 冲突时再查一次
|
|
|
+ *
|
|
|
+ * @param int $mainId 当前登录 xhMain.id
|
|
|
+ * @return array|null 邀请主数据行
|
|
|
+ */
|
|
|
+ public static function ensureByMainId($mainId)
|
|
|
+ {
|
|
|
+ $mainId = (int) $mainId;
|
|
|
+ if ($mainId <= 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ $row = self::getByMainId($mainId);
|
|
|
+ if (!empty($row)) {
|
|
|
+ return $row;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return self::createInviteeRecord($mainId, 0);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ $row = self::getByMainId($mainId);
|
|
|
+ if (!empty($row)) {
|
|
|
+ return $row;
|
|
|
+ }
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 按邀请码查 xhMainInvite
|
|
|
*/
|
|
|
@@ -41,7 +73,7 @@ class MainInviteClass extends BaseClass
|
|
|
/**
|
|
|
* 花店注册页:会员价与邀请减免(dict + 可选邀请码)
|
|
|
*/
|
|
|
- public static function resolveRegisterFeePreview($inviteCode = '')
|
|
|
+ public static function resolveRegisterFeePreview($inviteCode = '', $allowInviteBenefit = true)
|
|
|
{
|
|
|
$config = dict::getDict('hdRegisterConfig');
|
|
|
$price = round((float)($config['price'] ?? 0), 2);
|
|
|
@@ -58,6 +90,10 @@ class MainInviteClass extends BaseClass
|
|
|
'payAmount' => $price,
|
|
|
];
|
|
|
|
|
|
+ if (!$allowInviteBenefit) {
|
|
|
+ return $out;
|
|
|
+ }
|
|
|
+
|
|
|
$code = trim((string)$inviteCode);
|
|
|
if ($code === '') {
|
|
|
return $out;
|
|
|
@@ -92,9 +128,9 @@ class MainInviteClass extends BaseClass
|
|
|
/**
|
|
|
* 注册提交:费用 + 邀请人 mainId + 佣金快照
|
|
|
*/
|
|
|
- public static function resolveRegisterFeeSubmit($inviteCode = '')
|
|
|
+ public static function resolveRegisterFeeSubmit($inviteCode = '', $allowInviteBenefit = true)
|
|
|
{
|
|
|
- $preview = self::resolveRegisterFeePreview($inviteCode);
|
|
|
+ $preview = self::resolveRegisterFeePreview($inviteCode, $allowInviteBenefit);
|
|
|
$config = dict::getDict('hdRegisterConfig');
|
|
|
$configComm = round((float) ($config['commissionAmount'] ?? 0), 2);
|
|
|
|
|
|
@@ -103,6 +139,10 @@ class MainInviteClass extends BaseClass
|
|
|
$preview['inviterMainId'] = 0;
|
|
|
$preview['inviteCommissionAmount'] = 0;
|
|
|
|
|
|
+ if (!$allowInviteBenefit) {
|
|
|
+ return $preview;
|
|
|
+ }
|
|
|
+
|
|
|
if (!empty($preview['inviteNotFound'])) {
|
|
|
return $preview;
|
|
|
}
|
|
|
@@ -195,33 +235,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);
|
|
|
|
|
|
- $inviteCount = (int) ($inviter['inviteCount'] ?? 0) + 1;
|
|
|
- $totalCommission = round((float) ($inviter['totalCommission'] ?? 0) + $commissionAmount, 2);
|
|
|
- self::updateById((int) $inviter['id'], [
|
|
|
- 'inviteCount' => $inviteCount,
|
|
|
- 'totalCommission' => $totalCommission,
|
|
|
- ]);
|
|
|
+ // 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('操作进行中,请稍后再试');
|
|
|
+ }
|
|
|
+
|
|
|
+ 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::ensureByMainId($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;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|