- 在多个控制器中引入 SettlementPartyEnrichment 服务,以优化代理结算和账单的处理逻辑。 - 更新 AgentSettlementBillIndexController 和 AgentSettlementBillShowController,支持根据账单 ID 和关键字进行查询。 - 在 AgentSettlementPeriodCloseController 中添加对站点管理权限的验证,确保只有具备相应权限的管理员能够关闭账期。 - 在 AgentSettlementPeriodIndexController 中更新账期数据的返回格式,提升数据的完整性和可用性。 - 引入对相对占成比例的支持,增强代理资料的管理能力,确保数据一致性。
250 lines
9.9 KiB
PHP
250 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\Admin\AgentSettlement;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Services\AgentSettlement\SettlementPartyEnrichment;
|
|
use App\Support\AdminAgentSettlementScope;
|
|
use App\Support\ApiResponse;
|
|
use App\Support\PaginationTrait;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
final class AgentSettlementBillIndexController extends Controller
|
|
{
|
|
use PaginationTrait;
|
|
|
|
public function __construct(
|
|
private readonly SettlementPartyEnrichment $partyEnrichment,
|
|
) {}
|
|
|
|
public function __invoke(Request $request): JsonResponse
|
|
{
|
|
$admin = $request->lotteryAdmin();
|
|
abort_if($admin === null, 401);
|
|
|
|
$periodId = (int) $request->query('settlement_period_id', 0);
|
|
$adminSiteId = (int) $request->query('admin_site_id', 0);
|
|
|
|
$query = DB::table('settlement_bills as sb')
|
|
->leftJoin('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id')
|
|
->select([
|
|
'sb.*',
|
|
'sp.period_start',
|
|
'sp.period_end',
|
|
'sp.admin_site_id',
|
|
])
|
|
->orderByDesc('sb.id');
|
|
|
|
if ($periodId > 0) {
|
|
$query->where('sb.settlement_period_id', $periodId);
|
|
}
|
|
|
|
if ($adminSiteId > 0) {
|
|
$query->where('sp.admin_site_id', $adminSiteId);
|
|
}
|
|
|
|
$billId = (int) $request->query('bill_id', 0);
|
|
if ($billId > 0) {
|
|
$query->where('sb.id', $billId);
|
|
}
|
|
|
|
$billType = (string) $request->query('bill_type', '');
|
|
if ($billType !== '') {
|
|
$query->where('sb.bill_type', $billType);
|
|
}
|
|
|
|
$scope = (string) $request->query('scope', '');
|
|
match ($scope) {
|
|
'pending_confirm' => $query->where('sb.status', 'pending_confirm'),
|
|
'awaiting_payment' => $query
|
|
->whereIn('sb.status', ['confirmed', 'partial_paid', 'overdue'])
|
|
->where('sb.unpaid_amount', '>', 0),
|
|
'settled' => $query->where('sb.status', 'settled'),
|
|
'adjustment' => $query->whereIn('sb.bill_type', ['adjustment', 'reversal']),
|
|
default => null,
|
|
};
|
|
|
|
$keyword = trim((string) $request->query('keyword', ''));
|
|
if ($keyword !== '') {
|
|
$this->applyKeywordFilter($query, $keyword);
|
|
}
|
|
|
|
AdminAgentSettlementScope::applyToBillsQuery($query, $admin, 'sb');
|
|
|
|
$meta = $this->paginationMeta($request, defaultPerPage: 20, maxPerPage: 100);
|
|
$paginator = $query->paginate($meta['per_page'], ['sb.*', 'sp.period_start', 'sp.period_end', 'sp.admin_site_id'], 'page', $meta['page']);
|
|
|
|
/** @var Collection<int, object> $items */
|
|
$items = collect($paginator->items());
|
|
|
|
return ApiResponse::success([
|
|
'items' => $this->enrichBillRows($items),
|
|
'total' => $paginator->total(),
|
|
'page' => $paginator->currentPage(),
|
|
'per_page' => $paginator->perPage(),
|
|
]);
|
|
}
|
|
|
|
private function applyKeywordFilter(\Illuminate\Database\Query\Builder $query, string $keyword): void
|
|
{
|
|
$like = '%'.addcslashes($keyword, '%_\\').'%';
|
|
|
|
$query->where(function (\Illuminate\Database\Query\Builder $outer) use ($keyword, $like): void {
|
|
if (ctype_digit($keyword)) {
|
|
$outer->orWhere('sb.id', (int) $keyword)
|
|
->orWhere('sb.owner_id', (int) $keyword);
|
|
}
|
|
|
|
$outer->orWhere(function (\Illuminate\Database\Query\Builder $player) use ($like): void {
|
|
$player->where('sb.owner_type', 'player')
|
|
->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
|
|
$exists->selectRaw('1')
|
|
->from('players as p')
|
|
->whereColumn('p.id', 'sb.owner_id')
|
|
->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
|
|
$match->where('p.username', 'like', $like)
|
|
->orWhere('p.site_player_id', 'like', $like);
|
|
});
|
|
});
|
|
});
|
|
|
|
$outer->orWhere(function (\Illuminate\Database\Query\Builder $agent) use ($like): void {
|
|
$agent->where('sb.owner_type', 'agent')
|
|
->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
|
|
$exists->selectRaw('1')
|
|
->from('agent_nodes as a')
|
|
->whereColumn('a.id', 'sb.owner_id')
|
|
->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
|
|
$match->where('a.name', 'like', $like)
|
|
->orWhere('a.code', 'like', $like);
|
|
});
|
|
});
|
|
});
|
|
|
|
$outer->orWhere(function (\Illuminate\Database\Query\Builder $counter) use ($like): void {
|
|
$counter->where('sb.counterparty_type', 'agent')
|
|
->whereExists(function (\Illuminate\Database\Query\Builder $exists) use ($like): void {
|
|
$exists->selectRaw('1')
|
|
->from('agent_nodes as a')
|
|
->whereColumn('a.id', 'sb.counterparty_id')
|
|
->where(function (\Illuminate\Database\Query\Builder $match) use ($like): void {
|
|
$match->where('a.name', 'like', $like)
|
|
->orWhere('a.code', 'like', $like);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param Collection<int, object> $items
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
private function enrichBillRows(Collection $items): array
|
|
{
|
|
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->partyEnrichment->loadAgents($agentIds);
|
|
|
|
$out = [];
|
|
foreach ($items as $row) {
|
|
$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->partyEnrichment->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->partyEnrichment->formatPlayerUsername($player);
|
|
$item['player_site_player_id'] = $this->partyEnrichment->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->partyEnrichment->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->partyEnrichment->formatAgent($agents->get($ownerAgentId), $ownerAgentId);
|
|
$item['superior_agent_label'] = $counterType === 'platform'
|
|
? 'platform'
|
|
: $this->partyEnrichment->formatCounterpartyLabel($counterType, $counterId, $agents);
|
|
}
|
|
|
|
$out[] = $item;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @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->partyEnrichment->formatAgent($agents->get($id), $id);
|
|
}
|
|
|
|
return "{$type}#{$id}";
|
|
}
|
|
}
|