123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- <?php
- namespace App\Services\Coach;
- use App\Enums\OrderType;
- use App\Models\AgentInfo;
- use App\Models\MemberUser;
- use App\Models\Order;
- use App\Models\Wallet;
- use App\Models\WalletSplitRecord;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- class CommissionService
- {
- // 分佣比例配置
- private const COMMISSION_RATES = [
- 'travel' => [
- 'coach' => 0.9,
- 'platform' => 0.1,
- ],
- 'service' => [
- 'normal' => 0.5,
- 'overtime' => 0.7,
- ],
- 'inviter' => [
- 'first' => 0.2,
- 'second' => 0.1,
- ],
- 'profit' => [
- 'agent' => 0.4,
- 'platform' => 0.4,
- 'platform_no_agent' => 1.0,
- ],
- ];
- /**
- * 处理订单分佣
- */
- public function handleOrderCommission(Order $order): void
- {
- DB::transaction(function () use ($order) {
- try {
- // 处理路费分佣
- $this->handleTravelCommission($order);
- // 处理服务费分佣
- $profitAmount = $this->handleServiceCommission($order);
- // 处理邀请人分佣
- $inviterAmount = $this->handleInviterCommission($order, $profitAmount);
- // 处理代理商和平台分佣
- $this->handleAgentAndPlatformCommission($order, $profitAmount, $inviterAmount);
- } catch (\Exception $e) {
- Log::error('订单分佣失败', [
- 'order_id' => $order->id,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString(),
- ]);
- throw $e;
- }
- });
- }
- /**
- * 处理路费分佣
- */
- private function handleTravelCommission(Order $order): void
- {
- $travelAmount = $order->travel_amount;
- if ($travelAmount <= 0) {
- return;
- }
- // 技师路费分佣
- $coachRate = self::COMMISSION_RATES['travel']['coach'];
- $coachAmount = bcmul($travelAmount, $coachRate, 2);
- $this->updateWalletBalance($order->coach->wallet, $coachAmount, $order, 'coach', '技师路费分账');
- // 平台路费分佣
- $platformRate = self::COMMISSION_RATES['travel']['platform'];
- $platformAmount = bcmul($travelAmount, $platformRate, 2);
- $platformWallet = Wallet::where('owner_type', 'platform')->first();
- $this->updateWalletBalance($platformWallet, $platformAmount, $order, 'platform', '平台路费分账');
- Log::info('路费分佣完成', [
- 'order_id' => $order->id,
- 'travel_amount' => $travelAmount,
- 'coach_amount' => $coachAmount,
- 'platform_amount' => $platformAmount,
- ]);
- }
- /**
- * 处理服务费分佣
- */
- private function handleServiceCommission(Order $order): float
- {
- // 计算服务费(总金额减去路费)
- $serviceAmount = bcsub($order->amount, $order->travel_amount ?? 0, 2);
- // 获取分佣比例
- $rate = $order->type === OrderType::OVERTIME->value
- ? self::COMMISSION_RATES['service']['overtime']
- : self::COMMISSION_RATES['service']['normal'];
- // 计算技师分佣金额
- $commissionAmount = bcmul($serviceAmount, $rate, 2);
- // 更新技师钱包
- $this->updateWalletBalance(
- $order->coach->wallet,
- $commissionAmount,
- $order,
- 'coach',
- '技师服务佣金分账'
- );
- // 计算平台利润
- $profitAmount = bcsub($serviceAmount, $commissionAmount, 2);
- Log::info('服务费分佣完成', [
- 'order_id' => $order->id,
- 'service_amount' => $serviceAmount,
- 'commission_rate' => $rate,
- 'commission_amount' => $commissionAmount,
- 'profit_amount' => $profitAmount,
- ]);
- return $profitAmount;
- }
- /**
- * 处理邀请人分佣
- */
- private function handleInviterCommission(Order $order, float $profitAmount): float
- {
- $totalInviterAmount = 0;
- $user = MemberUser::with('inviter')->find($order->user_id);
- if (! $user || ! $user->inviter) {
- return $totalInviterAmount;
- }
- // 一级邀请人分佣
- $firstInviterAmount = $this->processInviter(
- $user->inviter,
- $profitAmount,
- self::COMMISSION_RATES['inviter']['first'],
- $order,
- '邀请人分账'
- );
- $totalInviterAmount = bcadd($totalInviterAmount, $firstInviterAmount, 2);
- // 二级邀请人分佣
- $secondInviter = $this->getSecondInviter($user);
- if ($secondInviter) {
- $secondInviterAmount = $this->processInviter(
- $secondInviter,
- $profitAmount,
- self::COMMISSION_RATES['inviter']['second'],
- $order,
- '二级邀请人分账'
- );
- $totalInviterAmount = bcadd($totalInviterAmount, $secondInviterAmount, 2);
- }
- return $totalInviterAmount;
- }
- /**
- * 处理代理商和平台分佣
- */
- private function handleAgentAndPlatformCommission(Order $order, float $profitAmount, float $inviterAmount): void
- {
- // 计算分佣基数
- $baseAmount = bcsub($profitAmount, $inviterAmount, 2);
- if ($order->agent_id) {
- // 代理商分佣
- $agentRate = self::COMMISSION_RATES['profit']['agent'];
- $agentAmount = bcmul($baseAmount, $agentRate, 2);
- $agent = AgentInfo::find($order->agent_id);
- $this->updateWalletBalance($agent->wallet, $agentAmount, $order, 'agent', '代理商分账');
- // 平台分佣
- $platformRate = self::COMMISSION_RATES['profit']['platform'];
- $platformAmount = bcmul($baseAmount, $platformRate, 2);
- } else {
- // 无代理商时平台获取全部收益
- $platformRate = self::COMMISSION_RATES['profit']['platform_no_agent'];
- $platformAmount = bcmul($baseAmount, $platformRate, 2);
- }
- // 记录平台分账
- $this->createSplitRecord($order->id, 1, 'platform_commission', $baseAmount, $platformRate, $platformAmount, '平台分账');
- }
- /**
- * 更新钱包余额并记录
- */
- private function updateWalletBalance(Wallet $wallet, float $amount, Order $order, string $role, string $remark): void
- {
- $wallet->increment('total_balance', $amount);
- $wallet->increment('available_balance', $amount);
- $wallet->save();
- // 记录交易
- $wallet->transRecords()->create([
- 'wallet_id' => $wallet->id,
- 'owner_id' => $order->id,
- 'owner_type' => Order::class,
- 'role' => $role,
- 'trans_type' => 1,
- 'storage_type' => 'balance',
- 'amount' => $amount,
- 'before_balance' => $wallet->available_balance - $amount,
- 'after_balance' => $wallet->available_balance,
- 'before_recharge_balance' => $wallet->recharge_balance,
- 'after_recharge_balance' => $wallet->recharge_balance,
- ]);
- }
- /**
- * 创建分账记录
- */
- private function createSplitRecord(int $orderId, int $ruleId, string $splitType, float $amount, float $ratio, float $splitAmount, string $remark): void
- {
- WalletSplitRecord::create([
- 'order_id' => $orderId,
- 'rule_id' => $ruleId,
- 'split_type' => $splitType,
- 'amount' => $amount,
- 'split_ratio' => $ratio,
- 'split_amount' => $splitAmount,
- 'entry_time' => now(),
- 'remark' => $remark,
- 'state' => 1,
- ]);
- }
- }
|