feat: 增强代理和玩家管理功能
- 在多个控制器中更新权限检查逻辑,确保管理员能够更灵活地管理代理和玩家。 - 在 AdminPlayerStoreController 中引入对玩家创建能力的验证,确保只有具备相应权限的管理员能够创建玩家。 - 更新请求验证逻辑,新增 credit_limit、rebate_rate 和 extra_rebate_rate 字段,以支持更细粒度的玩家管理。 - 在 AgentNodeProfileController 中添加对父代理能力授予的验证,确保子代理的权限在父代理范围内。 - 引入 AgentProfileFieldRules 以简化代理资料更新请求的规则定义,提升代码复用性。
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Models\AdminUser;
|
||||
use App\Models\AgentNode;
|
||||
use App\Models\AgentProfile;
|
||||
use App\Support\AdminAgentScope;
|
||||
use App\Support\AgentOverdueGuard;
|
||||
use App\Support\AgentSettlementCycle;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -16,6 +17,7 @@ final class AgentProfileService
|
||||
private readonly ShareRateValidator $shareRateValidator,
|
||||
private readonly CreditAllocationValidator $creditAllocationValidator,
|
||||
private readonly RebateLimitValidator $rebateLimitValidator,
|
||||
private readonly AgentCreditAllocatedSyncService $allocatedSync,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -39,10 +41,17 @@ final class AgentProfileService
|
||||
$previousCredit = (int) $profile->credit_limit;
|
||||
$isNew = ! $profile->exists;
|
||||
|
||||
if (! $isNew && $creditLimit < (int) $profile->allocated_credit) {
|
||||
throw ValidationException::withMessages([
|
||||
'credit_limit' => ['below_allocated'],
|
||||
]);
|
||||
if ($parent !== null && ! $isNew) {
|
||||
$this->allocatedSync->syncForAgent($parent);
|
||||
}
|
||||
|
||||
if (! $isNew) {
|
||||
$this->allocatedSync->syncForAgent($node);
|
||||
if ($creditLimit < (int) $profile->allocated_credit) {
|
||||
throw ValidationException::withMessages([
|
||||
'credit_limit' => ['below_allocated'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($parent !== null) {
|
||||
@@ -53,7 +62,7 @@ final class AgentProfileService
|
||||
}
|
||||
|
||||
if ($defaultRebate > $rebateLimit && $rebateLimit > 0) {
|
||||
throw \Illuminate\Validation\ValidationException::withMessages([
|
||||
throw ValidationException::withMessages([
|
||||
'default_player_rebate' => ['exceeds_limit'],
|
||||
]);
|
||||
}
|
||||
@@ -77,14 +86,7 @@ final class AgentProfileService
|
||||
$profile->save();
|
||||
|
||||
if ($parent !== null) {
|
||||
$parentProfile = AgentProfile::query()->where('agent_node_id', $parent->id)->first();
|
||||
if ($parentProfile !== null) {
|
||||
$creditDelta = $isNew ? $creditLimit : ($creditLimit - $previousCredit);
|
||||
if ($creditDelta !== 0) {
|
||||
$parentProfile->allocated_credit = max(0, (int) $parentProfile->allocated_credit + $creditDelta);
|
||||
$parentProfile->save();
|
||||
}
|
||||
}
|
||||
$this->allocatedSync->syncForAgent($parent);
|
||||
}
|
||||
|
||||
return $profile;
|
||||
@@ -96,6 +98,9 @@ final class AgentProfileService
|
||||
*/
|
||||
public function present(AgentProfile $profile): array
|
||||
{
|
||||
$this->allocatedSync->syncForAgentId((int) $profile->agent_node_id);
|
||||
$profile->refresh();
|
||||
|
||||
$available = max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit);
|
||||
|
||||
return [
|
||||
@@ -119,6 +124,65 @@ final class AgentProfileService
|
||||
return AgentProfile::query()->where('agent_node_id', $agentNodeId)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function parentCapsForNode(?AgentNode $parent): ?array
|
||||
{
|
||||
if ($parent === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->allocatedSync->syncForAgent($parent);
|
||||
|
||||
$profile = $this->profileForNode((int) $parent->id);
|
||||
if ($profile === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'agent_node_id' => (int) $parent->id,
|
||||
'total_share_rate' => (float) $profile->total_share_rate,
|
||||
'rebate_limit' => (float) $profile->rebate_limit,
|
||||
'available_credit' => max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit),
|
||||
];
|
||||
}
|
||||
|
||||
/** 玩家授信写入前:校验代理可下发是否足够(按当前库内已占用重算)。 */
|
||||
public function assertMayIncreasePlayerCredit(AgentNode $agent, int $additionalCredit): void
|
||||
{
|
||||
if ($additionalCredit <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->assertAgentProfileExists($agent);
|
||||
$this->allocatedSync->syncForAgent($agent);
|
||||
$this->creditAllocationValidator->assertPlayerCreditDeltaWithinAgent($agent, $additionalCredit);
|
||||
}
|
||||
|
||||
/** 玩家授信变更后:按直属玩家+直属下级代理重算已下发额度(无 profile 时跳过)。 */
|
||||
public function refreshAllocatedCredit(AgentNode $agent): void
|
||||
{
|
||||
$this->allocatedSync->syncForAgent($agent);
|
||||
}
|
||||
|
||||
public function adjustPlayerCreditAllocation(AgentNode $agent, int $previousLimit, int $newLimit, int $playerUsedCredit = 0): void
|
||||
{
|
||||
if ($newLimit < $playerUsedCredit) {
|
||||
throw ValidationException::withMessages([
|
||||
'credit_limit' => ['below_player_used'],
|
||||
]);
|
||||
}
|
||||
|
||||
$delta = $newLimit - $previousLimit;
|
||||
$this->assertAgentProfileExists($agent);
|
||||
$this->allocatedSync->syncForAgent($agent);
|
||||
|
||||
if ($delta > 0) {
|
||||
$this->creditAllocationValidator->assertPlayerCreditDeltaWithinAgent($agent, $delta);
|
||||
}
|
||||
}
|
||||
|
||||
public function assertActorMayCreateChildAgent(AdminUser $admin): void
|
||||
{
|
||||
if ($admin->isSuperAdmin()) {
|
||||
@@ -135,6 +199,12 @@ final class AgentProfileService
|
||||
'parent_id' => ['cannot_create_child_agent'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (AgentOverdueGuard::agentHasOverdueBills((int) $node->id)) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['agent_overdue'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function assertActorMayCreatePlayer(AdminUser $admin): void
|
||||
@@ -153,6 +223,12 @@ final class AgentProfileService
|
||||
'site_code' => ['cannot_create_player'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (AgentOverdueGuard::agentHasOverdueBills((int) $node->id)) {
|
||||
throw ValidationException::withMessages([
|
||||
'site_code' => ['agent_overdue'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,4 +269,15 @@ final class AgentProfileService
|
||||
|
||||
return $profile === null || $profile->can_create_player;
|
||||
}
|
||||
|
||||
private function assertAgentProfileExists(AgentNode $agent): void
|
||||
{
|
||||
if (AgentProfile::query()->where('agent_node_id', $agent->id)->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw ValidationException::withMessages([
|
||||
'credit_limit' => ['agent_profile_required'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user