fix(core): harden settlement and wallet integration

This commit is contained in:
wchino
2026-07-22 01:40:37 +08:00
parent 150c3e7ebd
commit 35f6e46958
54 changed files with 2564 additions and 359 deletions

View File

@@ -2,23 +2,26 @@
namespace App\Services\Admin;
use App\Models\AdminUser;
use App\Models\AuditLog;
use App\Support\AdminDataScope;
use App\Support\AdminScopeContext;
use App\Support\AdminScopeContextResolver;
use Carbon\Carbon;
use App\Models\Draw;
use App\Models\AuditLog;
use App\Models\RiskPool;
use App\Models\RiskPoolLockLog;
use App\Models\SettlementBatch;
use App\Models\AdminUser;
use App\Models\WalletTxn;
use App\Models\TicketItem;
use App\Models\TicketOrder;
use App\Models\TransferOrder;
use App\Models\WalletTxn;
use Carbon\Carbon;
use App\Services\AuditLogger;
use App\Support\LimitedQuery;
use App\Models\RiskPoolLockLog;
use App\Models\SettlementBatch;
use App\Support\AdminDataScope;
use App\Support\AdminScopeContext;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Query\Builder;
use App\Support\AdminScopeContextResolver;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\LengthAwarePaginator as PaginatorInstance;
use Illuminate\Support\Facades\DB;
/**
* 报表中心聚合查询(模块十三)。
@@ -498,7 +501,7 @@ final class AdminReportQueryService
->whereDate('d.business_date', '>=', $dateFrom)
->whereDate('d.business_date', '<=', $dateTo)
->selectRaw($providerCodeSql.' as provider_code')
->selectRaw("COALESCE(NULLIF(MAX(ti.provider_name), ''), MAX(bp.name), ".$providerCodeSql.") as provider_name")
->selectRaw("COALESCE(NULLIF(MAX(ti.provider_name), ''), MAX(bp.name), ".$providerCodeSql.') as provider_name')
->selectRaw('COUNT(ti.id) as ticket_item_count')
->selectRaw('SUM(ti.actual_deduct_amount) as total_bet_minor')
->selectRaw('SUM(ti.win_amount + ti.jackpot_win_amount) as total_payout_minor')
@@ -514,7 +517,7 @@ final class AdminReportQueryService
/**
* @return list<array<int, string|int|float|null>>
*/
public function reportRows(string $reportType, ?array $filterJson, AdminUser|AdminScopeContext|null $scope = null): array
public function reportRows(string $reportType, ?array $filterJson, AdminUser|AdminScopeContext $scope): array
{
$range = $this->resolveDateRange($filterJson);
$dateFrom = $range['date_from'];
@@ -526,7 +529,7 @@ final class AdminReportQueryService
'player_win_loss' => $this->playerWinLossExportRows($filterJson, $dateFrom, $dateTo, $scope),
'play_dimension_report' => $this->playDimensionExportRows($filterJson, $dateFrom, $dateTo, $scope),
'provider_profit_report' => $this->providerProfitExportRows($dateFrom, $dateTo, $scope),
'audit_operation_report' => $this->auditExportRows($filterJson, $dateFrom, $dateTo),
'audit_operation_report' => $this->auditExportRows($filterJson, $dateFrom, $dateTo, $scope),
'wallet_transfer_report', 'transfer_orders_daily' => $this->transferOrdersExportRows($filterJson, $dateFrom, $dateTo, $scope),
'wallet_txns_daily' => $this->walletTxnsExportRows($filterJson, $dateFrom, $dateTo, $scope),
'hot_number_risk_report' => $this->hotNumberRiskExportRows($filterJson),
@@ -645,27 +648,38 @@ final class AdminReportQueryService
foreach ($this->providerProfitPaginated($dateFrom, $dateTo, 1, 10_000, $scope)->items() as $row) {
$rows[] = [(string) $row->provider_code, (string) $row->provider_name, (int) $row->ticket_item_count, (int) $row->total_bet_minor, (int) $row->total_payout_minor, (int) $row->approx_house_gross_minor];
}
return $rows;
}
/**
* @return list<array<int, string|int|float|null>>
*/
private function auditExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
{
private function auditExportRows(
?array $filterJson,
string $dateFrom,
string $dateTo,
AdminUser|AdminScopeContext $scope,
): array {
$admin = $scope instanceof AdminScopeContext ? $scope->admin : $scope;
$operatorId = isset($filterJson['operator_id']) ? (int) $filterJson['operator_id'] : null;
$rows = [
['ID', '操作者类型', '操作者ID', '模块', '操作', 'IP', '时间'],
];
$q = AuditLog::query()->orderByDesc('id');
if (! $admin->isSuperAdmin()) {
// audit_logs 没有可靠的站点快照;普通审计账号仅能导出自己的后台操作。
$q->where('operator_type', AuditLogger::OPERATOR_ADMIN)
->where('operator_id', (int) $admin->getKey());
}
if ($operatorId !== null && $operatorId > 0) {
$q->where('operator_id', $operatorId);
}
$q->whereDate('created_at', '>=', $dateFrom)
->whereDate('created_at', '<=', $dateTo);
$limited = \App\Support\LimitedQuery::get($q, 5000);
$limited = LimitedQuery::get($q, 5000);
foreach ($limited['rows'] as $log) {
$rows[] = [
(int) $log->id,
@@ -685,7 +699,7 @@ final class AdminReportQueryService
return $rows;
}
/** @return \Illuminate\Database\Query\Builder */
/** @return Builder */
private function playerWinLossBaseQuery(
?int $playerId,
string $dateFrom,
@@ -725,7 +739,7 @@ final class AdminReportQueryService
return $query;
}
/** @return \Illuminate\Database\Query\Builder */
/** @return Builder */
private function playDimensionBaseQuery(?string $playCode, string $dateFrom, string $dateTo, AdminUser|AdminScopeContext|null $scope = null)
{
$context = $this->normalizeScope($scope);
@@ -755,9 +769,9 @@ final class AdminReportQueryService
/**
* @return list<array<int, string|int|float|null>>
*/
private function drawProfitExportRows(?array $filterJson, AdminUser|AdminScopeContext|null $scope = null): array
private function drawProfitExportRows(?array $filterJson, AdminUser|AdminScopeContext $scope): array
{
$context = $this->normalizeScope($scope);
$admin = $scope instanceof AdminScopeContext ? $scope->admin : $scope;
$draw = $this->resolveDrawForReport($filterJson);
if ($draw === null) {
return [['提示', '请提供 draw_id 或 draw_no']];
@@ -766,10 +780,8 @@ final class AdminReportQueryService
$drawId = (int) $draw->id;
$orderQuery = TicketOrder::query()->where('draw_id', $drawId);
$itemQuery = TicketItem::query()->where('draw_id', $drawId);
if ($context !== null) {
AdminDataScope::applyEloquentViaPlayer($orderQuery, $context->admin);
AdminDataScope::applyEloquentViaPlayer($itemQuery, $context->admin);
}
AdminDataScope::applyEloquentViaPlayer($orderQuery, $admin);
AdminDataScope::applyEloquentViaPlayer($itemQuery, $admin);
$totalBetMinor = (int) $orderQuery->sum('total_actual_deduct');
$orderCount = (int) $orderQuery->count();
@@ -805,11 +817,13 @@ final class AdminReportQueryService
],
];
$batches = SettlementBatch::query()
->where('draw_id', $drawId)
->orderByDesc('id')
->limit(100)
->get();
$batches = $admin->isSuperAdmin()
? SettlementBatch::query()
->where('draw_id', $drawId)
->orderByDesc('id')
->limit(100)
->get()
: collect();
foreach ($batches as $batch) {
$rows[] = [