feat: enhance agent management and validation logic

- Updated AGENTS.md to clarify agent account restrictions and permissions.
- Implemented checks in AgentNodeAdminUserStoreController and AgentNodeRoleStoreController to restrict admin user and role creation to the agent's own node.
- Enhanced validation in AdminPlayerStoreController and AdminPlayerUpdateController to enforce credit limit and rebate rate rules based on player funding mode.
- Refactored various request classes to utilize shared admin account field rules for consistency.
- Improved error handling in services related to credit allocation and rebate limits to ensure proper validation and messaging.
This commit is contained in:
2026-06-14 21:13:27 +08:00
parent 395e1c7400
commit 5b6d4cb74d
56 changed files with 1558 additions and 222 deletions

View File

@@ -14,7 +14,7 @@ final class TicketPreviewService
public function __construct(
private readonly PlayCatalogResolver $catalogResolver,
private readonly PlayRuleEngine $ruleEngine,
private readonly InstantRebateResolver $instantRebateResolver,
private readonly TicketLineInstantRebateApplicator $rebateApplicator,
private readonly RiskPoolService $riskPoolService,
private readonly DrawHallSnapshotBuilder $drawHallSnapshot,
) {}
@@ -65,7 +65,7 @@ final class TicketPreviewService
$resolved['play_config'],
$resolved['odds_items'],
);
$evaluated = $this->applyPlayerInstantRebate($player, $evaluated);
$evaluated = $this->rebateApplicator->apply($player, $evaluated);
$locks = array_map(fn (array $combo): array => [
'number_4d' => $combo['number_4d'],
@@ -81,7 +81,7 @@ final class TicketPreviewService
}
}
$rebateAmount = (int) $evaluated['total_bet_amount'] - (int) $evaluated['actual_deduct_amount'];
$rebateAmount = $this->rebateApplicator->displayRebateAmount($player, $evaluated);
$totalBet += (int) $evaluated['total_bet_amount'];
$totalRebate += $rebateAmount;
$totalActualDeduct += (int) $evaluated['actual_deduct_amount'];
@@ -130,42 +130,10 @@ final class TicketPreviewService
'total_rebate_amount' => $totalRebate,
'total_actual_deduct' => $totalActualDeduct,
'total_estimated_payout' => $totalEstimatedPayout,
'instant_rebate_applied' => ! PlayerFundingMode::usesCredit($player),
],
'lines' => $lines,
'warnings' => $warningRows,
];
}
/**
* @param array<string, mixed> $evaluated
* @return array<string, mixed>
*/
private function applyPlayerInstantRebate(Player $player, array $evaluated): array
{
$resolved = $this->instantRebateResolver->resolveForPlayer(
$player,
(string) $evaluated['play_code'],
(float) $evaluated['rebate_rate_snapshot'],
);
$evaluated['rule_snapshot_json']['base_rebate_rate'] = number_format($resolved['base_rebate_rate'], 4, '.', '');
$evaluated['rule_snapshot_json']['player_addon_rebate_rate'] = number_format($resolved['player_addon_rebate_rate'], 4, '.', '');
$evaluated['rule_snapshot_json']['rebate_inherited_from_agent'] = $resolved['inherited_from_agent'];
if (PlayerFundingMode::usesCredit($player)) {
$evaluated['rebate_rate_snapshot'] = '0.0000';
$evaluated['actual_deduct_amount'] = (int) $evaluated['total_bet_amount'];
return $evaluated;
}
$finalRate = $resolved['final_rebate_rate'];
$evaluated['rebate_rate_snapshot'] = number_format($finalRate, 4, '.', '');
$evaluated['actual_deduct_amount'] = max(
0,
(int) floor((int) $evaluated['total_bet_amount'] * (1 - $finalRate)),
);
return $evaluated;
}
}