AgentProfitCommissionProfileService.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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 Illuminate\Support\Facades\DB;
  7. /** 合营盈亏分成方案(只有总后台官方方案)。 */
  8. class AgentProfitCommissionProfileService
  9. {
  10. public function __construct(
  11. private AgentProfitCommissionAssignmentService $assignments,
  12. private AgentWalletService $wallets
  13. ) {
  14. }
  15. public function paginate(array $params): array
  16. {
  17. $page = max(1, (int) ($params['page'] ?? 1));
  18. $limit = min(100, max(1, (int) ($params['limit'] ?? 20)));
  19. $query = AgentProfitCommissionProfile::query()->whereNull('owner_agent_id');
  20. if (!empty($params['name'])) $query->where('name', 'like', '%' . $params['name'] . '%');
  21. $total = (clone $query)->count();
  22. $list = $query->withCount('agents')->orderBy('margin_amount')->orderByDesc('id')->forPage($page, $limit)->get();
  23. return compact('total', 'page', 'limit', 'list');
  24. }
  25. public function save(array $data, ?int $adminId = null): AgentProfitCommissionProfile
  26. {
  27. return DB::transaction(function () use ($data, $adminId) {
  28. $profile = empty($data['id'])
  29. ? new AgentProfitCommissionProfile()
  30. : AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')->lockForUpdate()->findOrFail($data['id']);
  31. $name = trim((string) $data['name']);
  32. if ($name === '') throw new \InvalidArgumentException('方案名称不能为空');
  33. $duplicate = AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')->where('name', $name)
  34. ->when($profile->exists, fn ($query) => $query->where('id', '<>', $profile->id))->exists();
  35. if ($duplicate) throw new \InvalidArgumentException('方案名称已存在');
  36. $profile->name = $name;
  37. $profile->margin_amount = bcadd((string) $data['margin_amount'], '0', 4);
  38. foreach (AgentProfitCommissionProfile::RATE_FIELDS as $field) {
  39. $profile->{$field} = bcadd((string) $data[$field], '0', 4);
  40. }
  41. if (!$profile->exists) $profile->is_default = 0;
  42. $changed = $profile->exists && $profile->isDirty(array_merge(AgentProfitCommissionProfile::RATE_FIELDS, ['margin_amount', 'name']));
  43. $profile->save();
  44. if ($changed) {
  45. // 已在使用该方案的代理:比例从现在起按新值计算,并按新保证金重新判断是否继续分成。
  46. $agentIds = Agent::query()->where('profit_commission_profile_id', $profile->id)->pluck('id')->all();
  47. $this->assignments->assignMany($agentIds, $profile, $adminId);
  48. foreach ($agentIds as $agentId) {
  49. $this->wallets->evaluateActivation(Agent::query()->lockForUpdate()->findOrFail($agentId));
  50. }
  51. }
  52. return $profile->fresh();
  53. });
  54. }
  55. public function delete(int $id): void
  56. {
  57. DB::transaction(function () use ($id) {
  58. $profile = AgentProfitCommissionProfile::query()->whereNull('owner_agent_id')->lockForUpdate()->findOrFail($id);
  59. if (Agent::query()->where('profit_commission_profile_id', $profile->id)->exists()) {
  60. throw new \RuntimeException('仍有代理使用该方案,不能删除');
  61. }
  62. if (AgentPlanApplication::query()->where('profile_id', $profile->id)->where('status', AgentPlanApplication::STATUS_PENDING)->exists()) {
  63. throw new \RuntimeException('该方案有待审核的申请,不能删除');
  64. }
  65. $profile->delete();
  66. });
  67. }
  68. }