|
@@ -0,0 +1,244 @@
|
|
|
+<?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,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+}
|