CommissionService.php 7.8 KB

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