WaterCommissionAccrual.php 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. <?php
  2. declare(strict_types=1);
  3. namespace plugin\saiadmin\app\service\agent;
  4. use DomainException;
  5. use plugin\saiadmin\app\model\water\WaterAgent;
  6. use plugin\saiadmin\app\model\water\WaterCommission;
  7. use plugin\saiadmin\app\model\water\WaterEnterprise;
  8. use plugin\saiadmin\app\model\water\WaterOrder;
  9. /** Record the direct agent's commission inside the paid-order transaction. */
  10. final class WaterCommissionAccrual
  11. {
  12. public function record(WaterOrder $order, WaterEnterprise $enterprise): void
  13. {
  14. // Historical demo orders are not real receipts and must not create payable commissions.
  15. if (str_starts_with($order->reference, 'TEST-') || str_contains($order->package_name, '测试')) {
  16. return;
  17. }
  18. $agent = $enterprise->agent;
  19. if (!$agent || (int) $agent->status !== 1) {
  20. return;
  21. }
  22. $level = $this->level($agent);
  23. if ($level === null) {
  24. return;
  25. }
  26. $baseAmount = (int) $order->amount_cents;
  27. $rate = WaterCommissionPolicy::rate($level, true);
  28. WaterCommission::query()->create([
  29. 'order_id' => (int) $order->id,
  30. 'enterprise_id' => (int) $enterprise->id,
  31. 'enterprise_name' => $enterprise->name,
  32. 'agent_id' => (int) $agent->id,
  33. 'agent_level' => $level,
  34. 'rate_basis_points' => $rate,
  35. 'base_amount_cents' => $baseAmount,
  36. 'amount_cents' => WaterCommissionPolicy::amountAtRate($baseAmount, $rate),
  37. 'status' => 'pending',
  38. 'created_at' => $order->created_at,
  39. ]);
  40. }
  41. private function level(WaterAgent $agent): ?int
  42. {
  43. $level = 1;
  44. $seen = [];
  45. while (true) {
  46. $id = (int) $agent->id;
  47. if (isset($seen[$id]) || $level > 3) {
  48. throw new DomainException('代理上下级关系异常,无法计提佣金');
  49. }
  50. $seen[$id] = true;
  51. if ($agent->parent_id === null) {
  52. return null;
  53. }
  54. if ((int) $agent->parent_id === 0) {
  55. return $level;
  56. }
  57. $agent = WaterAgent::query()->find((int) $agent->parent_id)
  58. ?? throw new DomainException('代理上级不存在,无法计提佣金');
  59. $level++;
  60. }
  61. }
  62. }