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