CommissionService.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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->traffic_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. if ($platformWallet) {
  78. $this->updateWalletBalance($platformWallet, $platformAmount, $order, 'platform', '平台路费分账');
  79. }
  80. }
  81. /**
  82. * 处理服务费分佣
  83. */
  84. private function handleServiceCommission(Order $order): float
  85. {
  86. // 计算服务费(总金额减去路费)
  87. $serviceAmount = bcsub($order->total_amount, $order->traffic_amount ?? 0, 2);
  88. // 获取分佣比例
  89. $rate = $order->type == OrderType::OVERTIME->value
  90. ? self::COMMISSION_RATES['service']['overtime']
  91. : self::COMMISSION_RATES['service']['normal'];
  92. // 计算技师分佣金额
  93. $commissionAmount = bcmul($serviceAmount, $rate, 2);
  94. // 更新技师钱包
  95. $this->updateWalletBalance(
  96. $order->coach->wallet,
  97. $commissionAmount,
  98. $order,
  99. 'coach',
  100. '技师服务佣金分账'
  101. );
  102. // 计算平台利润
  103. $profitAmount = bcsub($serviceAmount, $commissionAmount, 2);
  104. return $profitAmount;
  105. }
  106. /**
  107. * 处理邀请人分佣
  108. */
  109. private function handleInviterCommission(Order $order, float $profitAmount): float
  110. {
  111. $totalInviterAmount = 0;
  112. $user = MemberUser::with('inviter')->find($order->user_id);
  113. if (! $user || ! $user->inviter) {
  114. return $totalInviterAmount;
  115. }
  116. // 一级邀请人分佣
  117. $firstInviterAmount = $this->processInviter(
  118. $user->inviter,
  119. $profitAmount,
  120. self::COMMISSION_RATES['inviter']['first'],
  121. $order,
  122. '邀请人分账'
  123. );
  124. $totalInviterAmount = bcadd($totalInviterAmount, $firstInviterAmount, 2);
  125. // 二级邀请人分佣
  126. $secondInviter = $this->getSecondInviter($user);
  127. if ($secondInviter) {
  128. $secondInviterAmount = $this->processInviter(
  129. $secondInviter,
  130. $profitAmount,
  131. self::COMMISSION_RATES['inviter']['second'],
  132. $order,
  133. '二级邀请人分账'
  134. );
  135. $totalInviterAmount = bcadd($totalInviterAmount, $secondInviterAmount, 2);
  136. }
  137. return $totalInviterAmount;
  138. }
  139. /**
  140. * 处理代理商和平台分佣
  141. */
  142. private function handleAgentAndPlatformCommission(Order $order, float $profitAmount, float $inviterAmount): void
  143. {
  144. // 计算分佣基数
  145. $baseAmount = bcsub($profitAmount, $inviterAmount, 2);
  146. if ($order->agent_id) {
  147. // 代理商分佣
  148. $agentRate = self::COMMISSION_RATES['profit']['agent'];
  149. $agentAmount = bcmul($baseAmount, $agentRate, 2);
  150. $agent = AgentInfo::find($order->agent_id);
  151. $this->updateWalletBalance($agent->wallet, $agentAmount, $order, 'agent', '代理商分账');
  152. // 平台分佣
  153. $platformRate = self::COMMISSION_RATES['profit']['platform'];
  154. $platformAmount = bcmul($baseAmount, $platformRate, 2);
  155. } else {
  156. // 无代理商时平台获取全部收益
  157. $platformRate = self::COMMISSION_RATES['profit']['platform_no_agent'];
  158. $platformAmount = bcmul($baseAmount, $platformRate, 2);
  159. }
  160. // 记录平台分账
  161. $this->createSplitRecord($order->id, 1, SplitType::PlatformCommission->value, $baseAmount, $platformRate, $platformAmount, '平台分账');
  162. }
  163. /**
  164. * 更新钱包余额并记录
  165. */
  166. private function updateWalletBalance(Wallet $wallet, float $amount, Order $order, string $role, string $remark): void
  167. {
  168. $wallet->increment('total_balance', $amount);
  169. $wallet->increment('available_balance', $amount);
  170. // 增加总收入
  171. $wallet->increment('total_income', $amount);
  172. // 记录交易
  173. $wallet->transRecords()->create([
  174. 'wallet_id' => $wallet->id,
  175. 'owner_id' => $order->id,
  176. 'owner_type' => Order::class,
  177. 'role' => $role,
  178. 'trans_type' => 1,
  179. 'storage_type' => StorageType::Balance->value,
  180. 'amount' => $amount,
  181. 'before_balance' => $wallet->available_balance - $amount,
  182. 'after_balance' => $wallet->available_balance,
  183. 'before_recharge_balance' => $wallet->recharge_balance,
  184. 'after_recharge_balance' => $wallet->recharge_balance,
  185. ]);
  186. }
  187. /**
  188. * 创建分账记录
  189. */
  190. private function createSplitRecord(int $orderId, int $ruleId, int $splitType, float $amount, float $ratio, float $splitAmount, string $remark): void
  191. {
  192. WalletSplitRecord::create([
  193. 'order_id' => $orderId,
  194. 'rule_id' => $ruleId,
  195. 'split_type' => $splitType,
  196. 'amount' => $amount,
  197. 'split_ratio' => $ratio,
  198. 'split_amount' => $splitAmount,
  199. 'entry_time' => now(),
  200. 'remark' => $remark,
  201. 'state' => 1,
  202. ]);
  203. }
  204. }