Files
lotteryLaravel/app/Services/Agent/CreditAllocationValidator.php
kang 9d355aa853
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
lotterLaravel E2E / e2e-api (push) Has been cancelled
fix(ticket): 本地化调整工单时间线状态标签翻译
- 将工单时间线中的状态标签改为调用多语言翻译接口
- 新增多语言文件中对应时间线标签的翻译词条
- 统一使用请求中的本地语言环境渲染时间线标签
- 优化代理信用额度校验,抽取公共方法requireProfile
- 抛出更精确的校验异常信息,区分缺失和额度超出情况
2026-07-02 14:39:55 +08:00

100 lines
3.1 KiB
PHP

<?php
namespace App\Services\Agent;
use App\Models\AgentNode;
use App\Models\AgentProfile;
use App\Support\AgentOverdueGuard;
use Illuminate\Validation\ValidationException;
final class CreditAllocationValidator
{
public function __construct(
private readonly AgentCreditAllocatedSyncService $allocatedSync,
) {}
public function assertChildCreditLimitWithinParent(
AgentNode $parent,
int $previousChildLimit,
int $newChildLimit,
bool $isNewChild,
): void {
if ($newChildLimit < 0) {
throw ValidationException::withMessages([
'credit_limit' => ['invalid'],
]);
}
$this->allocatedSync->syncForAgent($parent);
$profile = $this->requireProfile($parent->id, 'parent_profile_required');
$available = max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit);
$floor = $isNewChild ? 0 : max(0, $previousChildLimit);
$maxAllowed = $floor + $available;
if ($newChildLimit > $maxAllowed) {
throw ValidationException::withMessages([
'credit_limit' => ['exceeds_available'],
]);
}
}
public function assertAllocationWithinParent(AgentNode $parent, int $additionalCredit): void
{
$this->allocatedSync->syncForAgent($parent);
$profile = $this->requireProfile($parent->id, 'parent_profile_required');
$available = max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit);
if ($additionalCredit > $available) {
throw ValidationException::withMessages([
'credit_limit' => ['exceeds_available'],
]);
}
}
public function assertPlayerCreditWithinAgent(AgentNode $agent, int $playerCreditLimit): void
{
if ($playerCreditLimit < 0) {
throw ValidationException::withMessages([
'credit_limit' => ['invalid'],
]);
}
$this->assertPlayerCreditDeltaWithinAgent($agent, $playerCreditLimit);
}
public function assertPlayerCreditDeltaWithinAgent(AgentNode $agent, int $additionalCredit): void
{
if ($additionalCredit <= 0) {
return;
}
AgentOverdueGuard::assertAgentMayGrantCredit((int) $agent->id);
$this->allocatedSync->syncForAgent($agent);
$profile = $this->requireProfile($agent->id, 'agent_profile_required');
$available = max(0, (int) $profile->credit_limit - (int) $profile->allocated_credit);
if ($additionalCredit > $available) {
throw ValidationException::withMessages([
'credit_limit' => ['exceeds_available'],
]);
}
}
private function requireProfile(int $agentNodeId, string $missingKey): AgentProfile
{
$profile = AgentProfile::query()->where('agent_node_id', $agentNodeId)->first();
if ($profile === null) {
throw ValidationException::withMessages([
'credit_limit' => [$missingKey],
]);
}
return $profile;
}
}