Files
lotteryLaravel/app/Http/Controllers/Api/V1/Admin/AgentSettlement/AgentSettlementBillIndexController.php
kang 980f3c9593 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.
2026-06-12 15:59:05 +08:00

142 lines
5.8 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->partyEnrichment->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);
});
});
});
});
}
}