CommissionService.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace App\Services\Coach;
  3. use App\Enums\OrderType;
  4. use App\Models\AgentInfo;
  5. use App\Models\MemberUser;
  6. use App\Models\Order;
  7. use App\Models\Wallet;
  8. use App\Models\WalletSplitRecord;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. class CommissionService
  12. {
  13. // 分佣比例配置
  14. private const COMMISSION_RATES = [
  15. 'travel' => [
  16. 'coach' => 0.9,
  17. 'platform' => 0.1,
  18. ],
  19. 'service' => [
  20. 'normal' => 0.5,
  21. 'overtime' => 0.7,
  22. ],
  23. 'inviter' => [
  24. 'first' => 0.2,
  25. 'second' => 0.1,
  26. ],
  27. 'profit' => [
  28. 'agent' => 0.4,
  29. 'platform' => 0.4,
  30. 'platform_no_agent' => 1.0,
  31. ],
  32. ];
  33. /**
  34. * 处理订单分佣
  35. */
  36. public function handleOrderCommission(Order $order): void
  37. {
  38. DB::transaction(function () use ($order) {
  39. try {
  40. // 处理路费分佣
  41. $this->handleTravelCommission($order);
  42. // 处理服务费分佣
  43. $profitAmount = $this->handleServiceCommission($order);
  44. // 处理邀请人分佣
  45. $inviterAmount = $this->handleInviterCommission($order, $profitAmount);
  46. // 处理代理商和平台分佣
  47. $this->handleAgentAndPlatformCommission($order, $profitAmount, $inviterAmount);
  48. } catch (\Exception $e) {
  49. Log::error('订单分佣失败', [
  50. 'order_id' => $order->id,
  51. 'error' => $e->getMessage(),
  52. 'trace' => $e->getTraceAsString(),
  53. ]);
  54. throw $e;
  55. }
  56. });
  57. }
  58. /**
  59. * 处理路费分佣
  60. */
  61. private function handleTravelCommission(Order $order): void
  62. {
  63. $travelAmount = $order->travel_amount;
  64. if ($travelAmount <= 0) {
  65. return;
  66. }
  67. // 技师路费分佣
  68. $coachRate = self::COMMISSION_RATES['travel']['coach'];
  69. $coachAmount = bcmul($travelAmount, $coachRate, 2);
  70. $this->updateWalletBalance($order->coach->wallet, $coachAmount, $order, 'coach', '技师路费分账');
  71. // 平台路费分佣
  72. $platformRate = self::COMMISSION_RATES['travel']['platform'];
  73. $platformAmount = bcmul($travelAmount, $platformRate, 2);
  74. $platformWallet = Wallet::where('owner_type', 'platform')->first();
  75. $this->updateWalletBalance($platformWallet, $platformAmount, $order, 'platform', '平台路费分账');
  76. Log::info('路费分佣完成', [
  77. 'order_id' => $order->id,
  78. 'travel_amount' => $travelAmount,
  79. 'coach_amount' => $coachAmount,
  80. 'platform_amount' => $platformAmount,
  81. ]);
  82. }
  83. /**
  84. * 处理服务费分佣
  85. */
  86. private function handleServiceCommission(Order $order): float
  87. {
  88. // 计算服务费(总金额减去路费)
  89. $serviceAmount = bcsub($order->amount, $order->travel_amount ?? 0, 2);
  90. // 获取分佣比例
  91. $rate = $order->type === OrderType::OVERTIME->value
  92. ? self::COMMISSION_RATES['service']['overtime']
  93. : self::COMMISSION_RATES['service']['normal'];
  94. // 计算技师分佣金额
  95. $commissionAmount = bcmul($serviceAmount, $rate, 2);
  96. // 更新技师钱包
  97. $this->updateWalletBalance(
  98. $order->coach->wallet,
  99. $commissionAmount,
  100. $order,
  101. 'coach',
  102. '技师服务佣金分账'
  103. );
  104. // 计算平台利润
  105. $profitAmount = bcsub($serviceAmount, $commissionAmount, 2);
  106. Log::info('服务费分佣完成', [
  107. 'order_id' => $order->id,
  108. 'service_amount' => $serviceAmount,
  109. 'commission_rate' => $rate,
  110. 'commission_amount' => $commissionAmount,
  111. 'profit_amount' => $profitAmount,
  112. ]);
  113. return $profitAmount;
  114. }
  115. /**
  116. * 处理邀请人分佣
  117. */
  118. private function handleInviterCommission(Order $order, float $profitAmount): float
  119. {
  120. $totalInviterAmount = 0;
  121. $user = MemberUser::with('inviter')->find($order->user_id);
  122. if (! $user || ! $user->inviter) {
  123. return $totalInviterAmount;
  124. }
  125. // 一级邀请人分佣
  126. $firstInviterAmount = $this->processInviter(
  127. $user->inviter,
  128. $profitAmount,
  129. self::COMMISSION_RATES['inviter']['first'],
  130. $order,
  131. '邀请人分账'
  132. );
  133. $totalInviterAmount = bcadd($totalInviterAmount, $firstInviterAmount, 2);
  134. // 二级邀请人分佣
  135. $secondInviter = $this->getSecondInviter($user);
  136. if ($secondInviter) {
  137. $secondInviterAmount = $this->processInviter(
  138. $secondInviter,
  139. $profitAmount,
  140. self::COMMISSION_RATES['inviter']['second'],
  141. $order,
  142. '二级邀请人分账'
  143. );
  144. $totalInviterAmount = bcadd($totalInviterAmount, $secondInviterAmount, 2);
  145. }
  146. return $totalInviterAmount;
  147. }
  148. /**
  149. * 处理代理商和平台分佣
  150. */
  151. private function handleAgentAndPlatformCommission(Order $order, float $profitAmount, float $inviterAmount): void
  152. {
  153. // 计算分佣基数
  154. $baseAmount = bcsub($profitAmount, $inviterAmount, 2);
  155. if ($order->agent_id) {
  156. // 代理商分佣
  157. $agentRate = self::COMMISSION_RATES['profit']['agent'];
  158. $agentAmount = bcmul($baseAmount, $agentRate, 2);
  159. $agent = AgentInfo::find($order->agent_id);
  160. $this->updateWalletBalance($agent->wallet, $agentAmount, $order, 'agent', '代理商分账');
  161. // 平台分佣
  162. $platformRate = self::COMMISSION_RATES['profit']['platform'];
  163. $platformAmount = bcmul($baseAmount, $platformRate, 2);
  164. } else {
  165. // 无代理商时平台获取全部收益
  166. $platformRate = self::COMMISSION_RATES['profit']['platform_no_agent'];
  167. $platformAmount = bcmul($baseAmount, $platformRate, 2);
  168. }
  169. // 记录平台分账
  170. $this->createSplitRecord($order->id, 1, 'platform_commission', $baseAmount, $platformRate, $platformAmount, '平台分账');
  171. }
  172. /**
  173. * 更新钱包余额并记录
  174. */
  175. private function updateWalletBalance(Wallet $wallet, float $amount, Order $order, string $role, string $remark): void
  176. {
  177. $wallet->increment('total_balance', $amount);
  178. $wallet->increment('available_balance', $amount);
  179. $wallet->save();
  180. // 记录交易
  181. $wallet->transRecords()->create([
  182. 'wallet_id' => $wallet->id,
  183. 'owner_id' => $order->id,
  184. 'owner_type' => Order::class,
  185. 'role' => $role,
  186. 'trans_type' => 1,
  187. 'storage_type' => 'balance',
  188. 'amount' => $amount,
  189. 'before_balance' => $wallet->available_balance - $amount,
  190. 'after_balance' => $wallet->available_balance,
  191. 'before_recharge_balance' => $wallet->recharge_balance,
  192. 'after_recharge_balance' => $wallet->recharge_balance,
  193. ]);
  194. }
  195. /**
  196. * 创建分账记录
  197. */
  198. private function createSplitRecord(int $orderId, int $ruleId, string $splitType, float $amount, float $ratio, float $splitAmount, string $remark): void
  199. {
  200. WalletSplitRecord::create([
  201. 'order_id' => $orderId,
  202. 'rule_id' => $ruleId,
  203. 'split_type' => $splitType,
  204. 'amount' => $amount,
  205. 'split_ratio' => $ratio,
  206. 'split_amount' => $splitAmount,
  207. 'entry_time' => now(),
  208. 'remark' => $remark,
  209. 'state' => 1,
  210. ]);
  211. }
  212. }