feat: enhance agent settlement features and improve data access controls

- Added new section in AGENTS.md detailing learned workspace facts for better understanding of settlement processes.
- Updated AgentNodeDestroyController to remove unnecessary checks for admin users.
- Enhanced AgentSettlement controllers to assert permissions for finance adjustments and bill operations.
- Improved query scopes in AgentSettlement services to ensure proper data access based on admin roles.
- Refactored methods in SettlementPartyEnrichment for better bill row enrichment and data handling.
- Introduced new methods in AdminAgentSettlementScope for managing agent node visibility and finance adjustments.
This commit is contained in:
2026-06-12 15:59:05 +08:00
parent e14b7b4569
commit 980f3c9593
47 changed files with 2403 additions and 187 deletions

View File

@@ -100,6 +100,7 @@ final class SettlementPartyEnrichment
return $map;
}
/** 结算展示:仅代理名称;编号为内部标识,无名称时才回退 code。 */
public function formatAgent(?object $agent, int $fallbackId): string
{
if ($agent === null) {
@@ -107,13 +108,13 @@ final class SettlementPartyEnrichment
}
$name = trim((string) ($agent->name ?? ''));
$code = trim((string) ($agent->code ?? ''));
if ($name !== '' && $code !== '') {
return "{$name} ({$code})";
if ($name !== '') {
return $name;
}
return $name !== '' ? $name : ($code !== '' ? $code : "agent#{$fallbackId}");
$code = trim((string) ($agent->code ?? ''));
return $code !== '' ? $code : "agent#{$fallbackId}";
}
public function formatPlayerUsername(?object $player): ?string
@@ -150,4 +151,129 @@ final class SettlementPartyEnrichment
return "{$type}#{$id}";
}
/**
* @param iterable<int, object> $rows
* @return list<array<string, mixed>>
*/
public function enrichBillRows(iterable $rows): array
{
$items = collect($rows);
if ($items->isEmpty()) {
return [];
}
$playerIds = [];
$agentIds = [];
foreach ($items as $row) {
if ((string) $row->owner_type === 'player') {
$playerIds[] = (int) $row->owner_id;
} elseif ((string) $row->owner_type === 'agent') {
$agentIds[] = (int) $row->owner_id;
}
if ((string) $row->counterparty_type === 'agent' && (int) $row->counterparty_id > 0) {
$agentIds[] = (int) $row->counterparty_id;
}
}
$players = $playerIds !== []
? DB::table('players')
->whereIn('id', array_unique($playerIds))
->select(['id', 'username', 'site_player_id', 'agent_node_id', 'funding_mode', 'auth_source'])
->get()
->keyBy('id')
: collect();
foreach ($players as $player) {
$aid = (int) ($player->agent_node_id ?? 0);
if ($aid > 0) {
$agentIds[] = $aid;
}
}
$agents = $this->loadAgents($agentIds);
$out = [];
foreach ($items as $row) {
$out[] = $this->enrichBillRowWithLookups($row, $players, $agents);
}
return $out;
}
/** @return array<string, mixed> */
public function enrichBillRow(object $row): array
{
return $this->enrichBillRows([$row])[0];
}
/**
* @param Collection<int, object> $players
* @param Collection<int, object> $agents
* @return array<string, mixed>
*/
private function enrichBillRowWithLookups(object $row, Collection $players, Collection $agents): array
{
$item = (array) $row;
$ownerType = (string) $row->owner_type;
$counterType = (string) $row->counterparty_type;
$counterId = (int) $row->counterparty_id;
$item['owner_label'] = $this->legacyOwnerLabel($ownerType, (int) $row->owner_id, $players, $agents);
$item['counterparty_label'] = $this->formatCounterpartyLabel($counterType, $counterId, $agents);
$item['player_username'] = null;
$item['player_site_player_id'] = null;
$item['player_id_display'] = null;
$item['direct_agent_label'] = null;
$item['superior_agent_label'] = null;
$item['owner_party_label'] = null;
if ($ownerType === 'player') {
$player = $players->get((int) $row->owner_id);
$item['player_username'] = $this->formatPlayerUsername($player);
$item['player_site_player_id'] = $this->formatPlayerSiteId($player);
$item['player_id_display'] = (int) $row->owner_id;
$item['owner_funding_mode'] = $player !== null ? (string) ($player->funding_mode ?? '') : null;
$item['owner_auth_source'] = $player !== null ? $player->auth_source : null;
$directId = $counterType === 'agent' ? $counterId : (int) ($player->agent_node_id ?? 0);
$line = $this->agentLineLabels($directId > 0 ? $directId : null, $agents);
$item['direct_agent_label'] = $line['direct_agent_label'];
$item['superior_agent_label'] = $line['parent_agent_label'];
} elseif ($ownerType === 'agent') {
$ownerAgentId = (int) $row->owner_id;
$item['owner_party_label'] = $this->formatAgent($agents->get($ownerAgentId), $ownerAgentId);
$item['superior_agent_label'] = $counterType === 'platform'
? 'platform'
: $this->formatCounterpartyLabel($counterType, $counterId, $agents);
}
return $item;
}
/**
* @param Collection<int, object> $players
* @param Collection<int, object> $agents
*/
private function legacyOwnerLabel(
string $type,
int $id,
Collection $players,
Collection $agents,
): string {
if ($type === 'player') {
$player = $players->get($id);
return $player !== null
? (string) ($player->username ?: $player->site_player_id ?: "player#{$id}")
: "player#{$id}";
}
if ($type === 'agent') {
return $this->formatAgent($agents->get($id), $id);
}
return "{$type}#{$id}";
}
}