| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- <?php
- namespace app\common\service;
- use think\facade\Db;
- use think\facade\Log;
- class CommissionService
- {
- /**
- * 获取分销设置
- */
- public function getDistributionSetting()
- {
- $setting = Db::table('ba_distribution_setting')
- ->order('id', 'desc')
- ->find();
- // 如果没有设置,返回默认值
- if (!$setting) {
- $setting = [
- 'default_rate' => 0.10, // 10%
- 'min_withdrawal' => 10.00,
- 'max_withdrawal' => 10000.00,
- 'withdrawal_fee_rate' => 0.01, // 1%
- ];
- }
- return $setting;
- }
- /**
- * 计算佣金
- */
- public function calculateCommission($orderAmount, $distributorId = 0)
- {
- if ($distributorId <= 0) {
- return [
- 'has_commission' => false,
- 'commission_rate' => 0,
- 'commission_amount' => 0
- ];
- }
- $setting = $this->getDistributionSetting();
- $commissionRate = ($setting['default_rate']/100) ?? 0.10;
- // 计算佣金金额
- $commissionAmount = bcmul($orderAmount, $commissionRate, 2);
- return [
- 'has_commission' => true,
- 'commission_rate' => $commissionRate,
- 'commission_amount' => $commissionAmount,
- 'setting' => $setting
- ];
- }
- /**
- * 创建分销记录
- */
- public function createDistributionRecord($data)
- {
- $recordData = [
- 'order_id' => $data['order_id'] ?? 0,
- 'product_id' => $data['product_id'] ?? 0,
- 'buyer_id' => $data['buyer_id'] ?? 0,
- 'distributor_id' => $data['distributor_id'] ?? 0,
- 'commission_rate' => $data['commission_rate'] ?? 0,
- 'commission_amount' => $data['commission_amount'] ?? 0,
- 'status' => 1, // 1=待结算
- 'create_time' => date('Y-m-d H:i:s')
- ];
- return Db::table('ba_distribution_record')->insertGetId($recordData);
- }
- /**
- * 更新分销记录状态
- */
- public function updateDistributionRecord($orderId, $status, $settleTime = null)
- {
- $updateData = [
- 'status' => $status,
- 'update_time' => date('Y-m-d H:i:s')
- ];
- if ($settleTime) {
- $updateData['settle_time'] = $settleTime;
- }
- return Db::table('ba_distribution_record')
- ->where('order_id', $orderId)
- ->update($updateData);
- }
- /**
- * 获取用户佣金统计
- */
- public function getUserCommissionSummary($userId)
- {
- $summary = Db::table('ba_distribution_record')
- ->where('distributor_id', $userId)
- ->field('
- COUNT(*) as total_orders,
- SUM(CASE WHEN status = 1 THEN commission_amount ELSE 0 END) as pending_amount,
- SUM(CASE WHEN status = 2 THEN commission_amount ELSE 0 END) as settled_amount,
- SUM(CASE WHEN status = 3 THEN commission_amount ELSE 0 END) as canceled_amount
- ')
- ->find();
- return $summary ?: [
- 'total_orders' => 0,
- 'pending_amount' => 0,
- 'settled_amount' => 0,
- 'canceled_amount' => 0
- ];
- }
- /**
- * 更新用户佣金表
- */
- public function updateUserCommission($userId)
- {
- $summary = $this->getUserCommissionSummary($userId);
- // 已结算的佣金可以作为当前佣金(可提现)
- $currentCommission = $summary['settled_amount'] ?? 0;
- $totalCommission = $summary['settled_amount'] + $summary['pending_amount'];
- // 检查用户佣金表是否有记录
- $userCommission = Db::table('ba_user_commission')
- ->where('user_id', $userId)
- ->find();
- $data = [
- 'total_commission' => $totalCommission,
- 'current_commission' => $currentCommission,
- 'update_time' => date('Y-m-d H:i:s')
- ];
- if ($userCommission) {
- // 更新
- Db::table('ba_user_commission')
- ->where('user_id', $userId)
- ->update($data);
- } else {
- // 创建
- $data['user_id'] = $userId;
- $data['promotion_link'] = $this->generatePromotionLink($userId);
- Db::table('ba_user_commission')->insert($data);
- }
- }
- /**
- * 处理订单佣金
- */
- public function processOrderCommission(int $orderId): bool
- {
- try {
- // 获取订单信息
- $order = Db::name('order')
- ->where('id', $orderId)
- ->where('pay_status', 1) // 已支付
- ->where('order_status', 'IN', [1, 3]) // 已确认或已完成
- ->where('is_commission', 0) // 未处理佣金
- ->find();
- if (!$order) {
- Log::info("订单不满足佣金处理条件: {$orderId}");
- return false;
- }
- // 如果有分销人,处理佣金
- if (!empty($order['distributor_id']) && $order['commission_amount'] > 0) {
- $distributorId = $order['distributor_id'];
- $commissionAmount = $order['commission_amount'];
- // 更新分销人佣金
- $this->addCommission($distributorId, $commissionAmount, [
- 'type' => 2, // 订单佣金
- 'order_id' => $orderId,
- 'from_user_id' => $order['user_id'],
- 'remark' => '订单佣金:' . $order['order_no'] . ',金额:¥' . $commissionAmount
- ]);
- // 标记订单佣金已处理
- Db::name('order')
- ->where('id', $orderId)
- ->update([
- 'is_commission' => 1,
- 'update_time' => date('Y-m-d H:i:s')
- ]);
- Log::info("订单佣金处理成功: 订单ID={$orderId}, 分销人ID={$distributorId}, 佣金={$commissionAmount}");
- }
- return true;
- } catch (\Throwable $e) {
- Log::error("处理订单佣金失败: " . $e->getMessage());
- return false;
- }
- }
- /**
- * 增加佣金
- */
- public function addCommission(int $userId, float $amount, array $extra = []): bool
- {
- try {
- if ($amount <= 0) {
- return false;
- }
- Db::startTrans();
- // 获取当前佣金
- $commission = Db::name('user_commission')
- ->where('user_id', $userId)
- ->lock(true)
- ->find();
- $balanceBefore = $commission ? $commission['current_commission'] : 0;
- $balanceAfter = $balanceBefore + $amount;
- if ($commission) {
- // 更新现有记录
- Db::name('user_commission')
- ->where('user_id', $userId)
- ->update([
- 'total_commission' => Db::raw('total_commission + ' . $amount),
- 'current_commission' => Db::raw('current_commission + ' . $amount),
- 'update_time' => date('Y-m-d H:i:s')
- ]);
- } else {
- // 创建新记录
- $promotionLink = $this->generatePromotionLink($userId);
- Db::name('user_commission')->insert([
- 'user_id' => $userId,
- 'total_commission' => $amount,
- 'current_commission' => $amount,
- 'withdrawn_commission' => 0.00,
- 'frozen_commission' => 0.00,
- 'promotion_link' => $promotionLink,
- 'invitation_count' => 0,
- 'total_invitation' => 0,
- 'update_time' => date('Y-m-d H:i:s')
- ]);
- }
- // 记录佣金流水
- Db::name('commission_flow')->insert([
- 'user_id' => $userId,
- 'order_id' => $extra['order_id'] ?? null,
- 'from_user_id' => $extra['from_user_id'] ?? null,
- 'type' => $extra['type'] ?? 1,
- 'amount' => $amount,
- 'balance_before' => $balanceBefore,
- 'balance_after' => $balanceAfter,
- 'remark' => $extra['remark'] ?? ('佣金增加:¥' . $amount),
- 'create_time' => date('Y-m-d H:i:s')
- ]);
- Db::commit();
- return true;
- } catch (\Throwable $e) {
- Db::rollback();
- Log::error("增加佣金失败: " . $e->getMessage());
- return false;
- }
- }
- /**
- * 处理提现
- */
- public function processWithdrawal(int $withdrawalId): bool
- {
- try {
- $withdrawal = Db::name('withdrawal_record')
- ->where('id', $withdrawalId)
- ->where('status', 0) // 待审核
- ->lock(true)
- ->find();
- if (!$withdrawal) {
- Log::warning("提现记录不存在或状态不符: {$withdrawalId}");
- return false;
- }
- $userId = $withdrawal['user_id'];
- $amount = $withdrawal['amount'];
- // 检查用户佣金是否足够
- $commission = Db::name('user_commission')
- ->where('user_id', $userId)
- ->find();
- if (!$commission || $commission['current_commission'] < $amount) {
- Log::warning("用户佣金不足: 用户ID={$userId}, 需要={$amount}, 当前={$commission['current_commission']}");
- return false;
- }
- Db::startTrans();
- // 扣除佣金
- $newCurrent = $commission['current_commission'] - $amount;
- $newWithdrawn = $commission['withdrawn_commission'] + $amount;
- Db::name('user_commission')
- ->where('user_id', $userId)
- ->update([
- 'current_commission' => $newCurrent,
- 'withdrawn_commission' => $newWithdrawn,
- 'update_time' => date('Y-m-d H:i:s')
- ]);
- // 记录佣金流水
- Db::name('commission_flow')->insert([
- 'user_id' => $userId,
- 'type' => 3, // 提现扣除
- 'amount' => -$amount,
- 'balance_before' => $commission['current_commission'],
- 'balance_after' => $newCurrent,
- 'remark' => '提现扣除:' . $withdrawal['withdrawal_no'] . ',金额:¥' . $amount,
- 'create_time' => date('Y-m-d H:i:s')
- ]);
- // 更新提现记录状态为审核通过(实际打款需要另外处理)
- Db::name('withdrawal_record')
- ->where('id', $withdrawalId)
- ->update([
- 'status' => 1, // 审核通过
- 'audit_time' => date('Y-m-d H:i:s'),
- 'current_balance' => $commission['current_commission'],
- 'balance_after' => $newCurrent,
- 'update_time' => date('Y-m-d H:i:s')
- ]);
- Db::commit();
- Log::info("提现处理成功: 提现ID={$withdrawalId}, 用户ID={$userId}, 金额={$amount}");
- return true;
- } catch (\Throwable $e) {
- Db::rollback();
- Log::error("处理提现失败: " . $e->getMessage());
- return false;
- }
- }
- /**
- * 获取用户佣金详情
- */
- public function getUserCommissionDetail(int $userId): array
- {
- try {
- // 佣金信息
- $commission = Db::name('user_commission')
- ->where('user_id', $userId)
- ->find();
- if (!$commission) {
- $commission = [
- 'total_commission' => 0.00,
- 'current_commission' => 0.00,
- 'withdrawn_commission' => 0.00,
- 'frozen_commission' => 0.00,
- 'promotion_link' => $this->generatePromotionLink($userId),
- 'invitation_count' => 0,
- 'total_invitation' => 0
- ];
- }
- // 最近佣金流水
- $flows = Db::name('commission_flow')
- ->where('user_id', $userId)
- ->order('create_time', 'desc')
- ->limit(50)
- ->select()
- ->toArray();
- // 统计今日/本月佣金
- $todayStart = date('Y-m-d 00:00:00');
- $monthStart = date('Y-m-01 00:00:00');
- $todayIncome = Db::name('commission_flow')
- ->where('user_id', $userId)
- ->where('amount', '>', 0)
- ->where('create_time', '>=', $todayStart)
- ->sum('amount');
- $monthIncome = Db::name('commission_flow')
- ->where('user_id', $userId)
- ->where('amount', '>', 0)
- ->where('create_time', '>=', $monthStart)
- ->sum('amount');
- return [
- 'commission' => $commission,
- 'flows' => $flows,
- 'stats' => [
- 'today_income' => $todayIncome ?: 0,
- 'month_income' => $monthIncome ?: 0
- ]
- ];
- } catch (\Throwable $e) {
- Log::error("获取用户佣金详情失败: " . $e->getMessage());
- return [
- 'commission' => [
- 'total_commission' => 0.00,
- 'current_commission' => 0.00,
- 'withdrawn_commission' => 0.00,
- 'frozen_commission' => 0.00,
- 'promotion_link' => '',
- 'invitation_count' => 0,
- 'total_invitation' => 0
- ],
- 'flows' => [],
- 'stats' => [
- 'today_income' => 0,
- 'month_income' => 0
- ]
- ];
- }
- }
- /**
- * 生成唯一邀请码
- */
- public function generateInvitationCode(): string
- {
- $maxAttempts = 10;
- $attempts = 0;
- while ($attempts < $maxAttempts) {
- // 方法1:使用数字+字母组合
- $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // 去掉容易混淆的字符
- $code = '';
- for ($i = 0; $i < 6; $i++) {
- $code .= $chars[mt_rand(0, strlen($chars) - 1)];
- }
- // 方法2:或者使用更短的邀请码
- // $code = strtoupper(substr(md5(uniqid()), 0, 6));
- // 检查邀请码是否已存在
- $exists = Db::table('ba_user')
- ->where('invitation_code', $code)
- ->count();
- if (!$exists) {
- return $code;
- }
- $attempts++;
- // 如果冲突,尝试不同的算法
- if ($attempts >= 5) {
- $code = 'INV' . mt_rand(1000, 9999);
- $exists = Db::table('ba_user')
- ->where('invitation_code', $code)
- ->count();
- if (!$exists) {
- return $code;
- }
- }
- }
- // 如果还是冲突,使用时间戳+随机数
- return 'INV' . time() . mt_rand(10, 99);
- }
- /**
- * 生成推广链接
- */
- private function generatePromotionLink(int $userId): string
- {
- // 获取用户的邀请码
- $user = Db::table('ba_user')
- ->where('id', $userId)
- ->field('invitation_code')
- ->find();
- $invitationCode = $user['invitation_code'] ?? '';
- if (empty($invitationCode)) {
- // 如果用户还没有邀请码,先生成一个
- $invitationCode = $this->generateInvitationCode();
- Db::table('ba_user')
- ->where('id', $userId)
- ->update(['invitation_code' => $invitationCode]);
- }
- $domain = request()->domain();
- return $domain . '/#/user/register?invite=' . $invitationCode;
- }
- }
|