AgentProfitCommissionAssignmentService.php 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. namespace App\Services\Agent;
  3. use App\Models\Agent\Agent;
  4. use App\Models\Agent\AgentCommission;
  5. use App\Models\Agent\AgentProfitCommissionAssignment;
  6. use App\Models\Agent\AgentProfitCommissionProfile;
  7. use App\Models\Agent\AgentRebateRecord;
  8. use Carbon\Carbon;
  9. use Illuminate\Support\Facades\DB;
  10. class AgentProfitCommissionAssignmentService
  11. {
  12. public function at(Agent $agent, string $date): AgentProfitCommissionAssignment
  13. {
  14. $day = Carbon::parse($date)->toDateString();
  15. $assignment = AgentProfitCommissionAssignment::query()
  16. ->where('agent_id', $agent->id)
  17. ->where('effective_from', '<=', $day)
  18. ->orderByDesc('effective_from')
  19. ->orderByDesc('id')
  20. ->first();
  21. if (!$assignment) {
  22. throw new \RuntimeException("代理 {$agent->id} 缺少 {$day} 可用的盈亏佣金比例历史");
  23. }
  24. return $assignment;
  25. }
  26. public function assign(
  27. Agent $agent,
  28. AgentProfitCommissionProfile $profile,
  29. string $effectiveFrom,
  30. ?int $createdBy = null
  31. ): AgentProfitCommissionAssignment {
  32. $this->assignMany([(int) $agent->id], $profile, $effectiveFrom, $createdBy);
  33. return AgentProfitCommissionAssignment::query()
  34. ->where('agent_id', $agent->id)
  35. ->where('effective_from', Carbon::parse($effectiveFrom)->toDateString())
  36. ->firstOrFail();
  37. }
  38. public function assignMany(
  39. array $agentIds,
  40. AgentProfitCommissionProfile $profile,
  41. string $effectiveFrom,
  42. ?int $createdBy = null
  43. ): void {
  44. $agentIds = array_values(array_unique(array_map('intval', $agentIds)));
  45. if ($agentIds === []) return;
  46. $day = Carbon::parse($effectiveFrom)->toDateString();
  47. $this->assertMutable($agentIds, $day);
  48. $values = array_merge($profile->rateSnapshot(), [
  49. 'profit_commission_profile_id' => (int) $profile->id,
  50. 'profile_name' => (string) $profile->name,
  51. 'created_by' => $createdBy,
  52. ]);
  53. DB::transaction(function () use ($agentIds, $day, $values) {
  54. foreach (array_chunk($agentIds, 500) as $chunk) {
  55. foreach ($chunk as $agentId) {
  56. AgentProfitCommissionAssignment::query()->updateOrCreate(
  57. ['agent_id' => $agentId, 'effective_from' => $day],
  58. $values
  59. );
  60. }
  61. }
  62. });
  63. }
  64. private function assertMutable(array $agentIds, string $day): void
  65. {
  66. $newCredited = AgentRebateRecord::query()->whereIn('agent_id', $agentIds)
  67. ->where('settlement_date', '>=', $day)
  68. ->where('profit_status', AgentRebateRecord::STATUS_CREDITED)
  69. ->exists();
  70. $legacyCredited = AgentCommission::query()->whereIn('agent_id', $agentIds)
  71. ->where('type', 'profit')
  72. ->where('settlement_date', '>=', $day)
  73. ->where('status', AgentRebateRecord::STATUS_CREDITED)
  74. ->exists();
  75. if ($newCredited || $legacyCredited) {
  76. throw new \RuntimeException('生效日期已有盈亏佣金入账,不能修改比例方案');
  77. }
  78. }
  79. }