AgentPlanApplicationService.php 5.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. namespace App\Services\Agent;
  3. use App\Models\Agent\Agent;
  4. use App\Models\Agent\AgentPlanApplication;
  5. use App\Models\Agent\AgentProfitCommissionProfile;
  6. use App\Models\Agent\AgentSetting;
  7. use Illuminate\Support\Facades\DB;
  8. /**
  9. * 合营代理申请分成方案(方案由总后台配置),总后台审核通过后立即生效。
  10. * 已有方案的代理不能切换方案;只有还没有方案(含申请被驳回)的代理可以重新申请。
  11. */
  12. class AgentPlanApplicationService
  13. {
  14. public function __construct(
  15. private AgentProfitCommissionAssignmentService $assignments,
  16. private AgentWalletService $wallets
  17. ) {
  18. }
  19. public function plans(Agent $agent): array
  20. {
  21. $agent->loadMissing('profitCommissionProfile');
  22. return [
  23. 'current_profile' => $agent->profitCommissionProfile,
  24. 'profit_active' => (int) $agent->profit_active,
  25. 'margin_stop_percent' => (string) AgentSetting::current()->margin_stop_percent,
  26. 'pending_application' => AgentPlanApplication::query()->where('agent_id', $agent->id)
  27. ->where('status', AgentPlanApplication::STATUS_PENDING)->latest('id')->first(),
  28. 'list' => AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')
  29. ->orderBy('margin_amount')->orderBy('id')->get(),
  30. ];
  31. }
  32. public function apply(Agent $agent, int $profileId, string $remark = ''): AgentPlanApplication
  33. {
  34. return DB::transaction(function () use ($agent, $profileId, $remark) {
  35. $agent = Agent::query()->lockForUpdate()->findOrFail($agent->id);
  36. if (!$agent->isJoint()) throw new \RuntimeException('只有合营代理可以申请分成方案');
  37. $profile = AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')->findOrFail($profileId);
  38. if ($agent->profit_commission_profile_id) throw new \RuntimeException('已有分成方案,不能切换');
  39. if (AgentPlanApplication::query()->where('agent_id', $agent->id)->where('status', AgentPlanApplication::STATUS_PENDING)->exists()) {
  40. throw new \RuntimeException('已有待审核的方案申请');
  41. }
  42. return AgentPlanApplication::query()->create([
  43. 'agent_id' => $agent->id, 'profile_id' => $profile->id, 'profile_name' => $profile->name,
  44. 'status' => AgentPlanApplication::STATUS_PENDING, 'remark' => trim($remark),
  45. ]);
  46. });
  47. }
  48. public function paginate(array $params, ?Agent $agent = null): array
  49. {
  50. $page = max(1, (int) ($params['page'] ?? 1));
  51. $limit = min(100, max(1, (int) ($params['limit'] ?? 20)));
  52. $query = AgentPlanApplication::query()->with(['agent:id,type,username,real_name,balance,margin_amount', 'profile']);
  53. if ($agent) $query->where('agent_id', $agent->id);
  54. if (!empty($params['id'])) $query->where('id', (int) $params['id']);
  55. if (!empty($params['agent_id'])) $query->where('agent_id', (int) $params['agent_id']);
  56. if (!empty($params['status'])) $query->where('status', $params['status']);
  57. if (!empty($params['username'])) {
  58. $query->whereHas('agent', fn ($q) => $q->where('username', 'like', '%' . $params['username'] . '%'));
  59. }
  60. $total = (clone $query)->count();
  61. $list = $query->orderByDesc('id')->forPage($page, $limit)->get();
  62. return compact('total', 'page', 'limit', 'list');
  63. }
  64. public function audit(int $id, string $status, int $adminId, string $reason = ''): AgentPlanApplication
  65. {
  66. return DB::transaction(function () use ($id, $status, $adminId, $reason) {
  67. $application = AgentPlanApplication::query()->lockForUpdate()->findOrFail($id);
  68. if ($application->status !== AgentPlanApplication::STATUS_PENDING) throw new \RuntimeException('申请已审核');
  69. $agent = Agent::query()->lockForUpdate()->findOrFail($application->agent_id);
  70. if ($status === AgentPlanApplication::STATUS_APPROVED) {
  71. $profile = AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')->find($application->profile_id);
  72. if (!$profile) throw new \RuntimeException('方案已删除,请驳回');
  73. if (!$agent->isJoint()) throw new \RuntimeException('只有合营代理可以使用分成方案');
  74. if ($agent->profit_commission_profile_id) throw new \RuntimeException('代理已有分成方案,不能切换,请驳回');
  75. $agent->profit_commission_profile_id = $profile->id;
  76. $agent->save();
  77. $this->assignments->assign($agent, $profile, $adminId);
  78. $this->wallets->evaluateActivation($agent);
  79. } else {
  80. $reason = trim($reason);
  81. if ($reason === '') throw new \InvalidArgumentException('请填写驳回原因');
  82. $application->reject_reason = $reason;
  83. }
  84. $application->status = $status;
  85. $application->reviewed_by = $adminId;
  86. $application->reviewed_at = now();
  87. $application->save();
  88. return $application->fresh(['agent:id,type,username,profit_active', 'profile']);
  89. });
  90. }
  91. }