feat: enhance admin role management and reconciliation features
- Updated AGENTS.md to clarify site admin roles and their associated permissions. - Refactored reconciliation controllers to include admin user validation and improved access control based on admin roles. - Enhanced AdminReconcileJobService to support player-specific reconciliation and site-based job creation. - Removed deprecated rebate commission report functionality from the API and related services. - Improved dashboard overview builders to accommodate new site operator roles and their specific functionalities.
This commit is contained in:
@@ -17,7 +17,7 @@ use App\Support\AdminDataScope;
|
||||
use App\Support\AdminScopeContext;
|
||||
use App\Support\AdminAgentScope;
|
||||
use App\Support\AdminScopeContextResolver;
|
||||
use App\Support\SitePlatformRole;
|
||||
use App\Support\SiteOperatorRoles;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
|
||||
/**
|
||||
@@ -32,6 +32,8 @@ final class AdminDashboardSnapshotBuilder
|
||||
private readonly AdminReportQueryService $reportQuery,
|
||||
private readonly AgentDashboardOverviewBuilder $agentOverview,
|
||||
private readonly SiteDashboardOverviewBuilder $siteOverview,
|
||||
private readonly SiteFinanceDashboardOverviewBuilder $siteFinanceOverview,
|
||||
private readonly SiteCsDashboardOverviewBuilder $siteCsOverview,
|
||||
) {}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
@@ -60,12 +62,19 @@ final class AdminDashboardSnapshotBuilder
|
||||
],
|
||||
'agent_overview' => null,
|
||||
'site_overview' => null,
|
||||
'site_finance_overview' => null,
|
||||
'site_cs_overview' => null,
|
||||
];
|
||||
|
||||
if ($admin->primaryAgentNode() !== null) {
|
||||
$out['agent_overview'] = $this->agentOverview->build($admin);
|
||||
} elseif (SitePlatformRole::userHasSiteAdminRole($admin)) {
|
||||
$out['site_overview'] = $this->siteOverview->build($admin, $scope);
|
||||
} elseif (SiteOperatorRoles::userHasSiteOperatorRole($admin)) {
|
||||
$operatorSlug = SiteOperatorRoles::primarySiteOperatorSlug($admin);
|
||||
match ($operatorSlug) {
|
||||
SiteOperatorRoles::SLUG_SITE_FINANCE => $out['site_finance_overview'] = $this->siteFinanceOverview->build($admin, $scope),
|
||||
SiteOperatorRoles::SLUG_SITE_CS => $out['site_cs_overview'] = $this->siteCsOverview->build($admin),
|
||||
default => $out['site_overview'] = $this->siteOverview->build($admin, $scope),
|
||||
};
|
||||
}
|
||||
|
||||
if ($canDraw) {
|
||||
|
||||
@@ -4,11 +4,17 @@ namespace App\Services\Admin;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\Player;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\ReconcileJob;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ReconcileItem;
|
||||
use App\Lottery\ErrorCode;
|
||||
use App\Services\AuditLogger;
|
||||
use App\Support\AdminReconcileScope;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use App\Support\AdminSiteScope;
|
||||
use App\Support\ApiMessage;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\Wallet\WalletTransferReconcileDetector;
|
||||
|
||||
@@ -102,6 +108,23 @@ final class AdminReconcileJobService
|
||||
$periodEnd ??= now()->endOfDay();
|
||||
$periodStart ??= $periodEnd->copy()->startOfDay();
|
||||
|
||||
$player = null;
|
||||
if ($playerId !== null) {
|
||||
$player = Player::query()->find($playerId);
|
||||
if ($player === null || ! AdminSiteScope::playerAccessible($admin, $player)) {
|
||||
abort(ApiMessage::errorResponse(
|
||||
$request,
|
||||
'admin.site_player_access_denied',
|
||||
ErrorCode::AdminForbidden->value,
|
||||
null,
|
||||
403,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$scope = AdminScopePolicy::resolveContext($request, $admin);
|
||||
$adminSiteId = AdminReconcileScope::resolveAdminSiteIdForJob($admin, $player);
|
||||
|
||||
[$items] = $this->detector->scanItems(
|
||||
$periodStart,
|
||||
$periodEnd,
|
||||
@@ -109,9 +132,17 @@ final class AdminReconcileJobService
|
||||
staleMinutes: 15,
|
||||
playerId: $playerId,
|
||||
includeMainSiteCheck: true,
|
||||
scope: $scope,
|
||||
);
|
||||
|
||||
$job = $this->detector->persistJob($items, $periodStart, $periodEnd, (int) $admin->getKey());
|
||||
$job = $this->detector->persistJob(
|
||||
$items,
|
||||
$periodStart,
|
||||
$periodEnd,
|
||||
(int) $admin->getKey(),
|
||||
$adminSiteId,
|
||||
$playerId,
|
||||
);
|
||||
|
||||
AuditLogger::recordForAdmin(
|
||||
$admin,
|
||||
|
||||
@@ -478,19 +478,6 @@ final class AdminReportQueryService
|
||||
return $query->paginate($perPage, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
public function rebateCommissionPaginated(
|
||||
?string $playCode,
|
||||
string $dateFrom,
|
||||
string $dateTo,
|
||||
int $page,
|
||||
int $perPage,
|
||||
AdminUser|AdminScopeContext|null $scope = null,
|
||||
): LengthAwarePaginator {
|
||||
$query = $this->rebateCommissionBaseQuery($playCode, $dateFrom, $dateTo, $scope);
|
||||
|
||||
return $query->paginate($perPage, ['*'], 'page', $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<int, string|int|float|null>>
|
||||
*/
|
||||
@@ -505,7 +492,6 @@ final class AdminReportQueryService
|
||||
'daily_profit_summary' => $this->dailyProfitExportRows($dateFrom, $dateTo, $scope),
|
||||
'player_win_loss' => $this->playerWinLossExportRows($filterJson, $dateFrom, $dateTo, $scope),
|
||||
'play_dimension_report' => $this->playDimensionExportRows($filterJson, $dateFrom, $dateTo, $scope),
|
||||
'rebate_commission_report' => $this->rebateCommissionExportRows($filterJson, $dateFrom, $dateTo, $scope),
|
||||
'audit_operation_report' => $this->auditExportRows($filterJson, $dateFrom, $dateTo),
|
||||
'wallet_transfer_report', 'transfer_orders_daily' => $this->transferOrdersExportRows($filterJson, $dateFrom, $dateTo, $scope),
|
||||
'wallet_txns_daily' => $this->walletTxnsExportRows($filterJson, $dateFrom, $dateTo, $scope),
|
||||
@@ -546,7 +532,6 @@ final class AdminReportQueryService
|
||||
'hot_number_risk_report' => '热门号码风险报表',
|
||||
'play_dimension_report' => '玩法维度报表',
|
||||
'sold_out_number_report' => '售罄号码报表',
|
||||
'rebate_commission_report' => '佣金回水报表',
|
||||
'audit_operation_report' => '后台操作审计报表',
|
||||
default => $reportType,
|
||||
};
|
||||
@@ -618,28 +603,6 @@ final class AdminReportQueryService
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<int, string|int|float|null>>
|
||||
*/
|
||||
private function rebateCommissionExportRows(?array $filterJson, string $dateFrom, string $dateTo, AdminUser|AdminScopeContext|null $scope = null): array
|
||||
{
|
||||
$playCode = isset($filterJson['play_code']) ? trim((string) $filterJson['play_code']) : null;
|
||||
$rows = [
|
||||
['玩法', '回水', '订单数', '注单数'],
|
||||
];
|
||||
$items = $this->rebateCommissionBaseQuery($playCode !== '' ? $playCode : null, $dateFrom, $dateTo, $scope)->get();
|
||||
foreach ($items as $row) {
|
||||
$rows[] = [
|
||||
(string) $row->play_code,
|
||||
(int) $row->total_rebate_minor,
|
||||
(int) $row->order_count,
|
||||
(int) $row->ticket_item_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<int, string|int|float|null>>
|
||||
*/
|
||||
@@ -739,31 +702,6 @@ final class AdminReportQueryService
|
||||
return $query;
|
||||
}
|
||||
|
||||
/** @return \Illuminate\Database\Query\Builder */
|
||||
private function rebateCommissionBaseQuery(?string $playCode, string $dateFrom, string $dateTo, AdminUser|AdminScopeContext|null $scope = null)
|
||||
{
|
||||
$context = $this->normalizeScope($scope);
|
||||
$query = DB::table('ticket_items as ti')
|
||||
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
||||
->join('draws as d', 'd.id', '=', 'o.draw_id')
|
||||
->selectRaw('ti.play_code')
|
||||
->selectRaw('SUM(ti.total_bet_amount - ti.actual_deduct_amount) as total_rebate_minor')
|
||||
->selectRaw('COUNT(DISTINCT o.id) as order_count')
|
||||
->selectRaw('COUNT(ti.id) as ticket_item_count')
|
||||
->whereDate('d.business_date', '>=', $dateFrom)
|
||||
->whereDate('d.business_date', '<=', $dateTo)
|
||||
->groupBy('ti.play_code')
|
||||
->orderBy('ti.play_code');
|
||||
|
||||
if ($playCode !== null && $playCode !== '') {
|
||||
$query->where('ti.play_code', $playCode);
|
||||
}
|
||||
|
||||
AdminDataScope::applyToTicketOrdersViaPlayer($query, $context?->admin, 'o');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<int, string|int|float|null>>
|
||||
*/
|
||||
|
||||
62
app/Services/Admin/SiteCsDashboardOverviewBuilder.php
Normal file
62
app/Services/Admin/SiteCsDashboardOverviewBuilder.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\Player;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/** 站点客服仪表盘:玩家规模与今日注单活跃度,不含全局盈亏。 */
|
||||
final class SiteCsDashboardOverviewBuilder
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function build(AdminUser $admin): ?array
|
||||
{
|
||||
if (! $admin->hasPermissionCode('dashboard.view')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$site = SiteDashboardSiteResolver::resolvePrimarySite($admin);
|
||||
if ($site === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$siteId = (int) $site->id;
|
||||
$siteCode = (string) $site->code;
|
||||
$today = now()->toDateString();
|
||||
$activity = $this->todayTicketStats($siteCode, $today);
|
||||
|
||||
return [
|
||||
'admin_site_id' => $siteId,
|
||||
'site_code' => $siteCode,
|
||||
'site_name' => (string) $site->name,
|
||||
'player_count' => (int) Player::query()->where('site_code', $siteCode)->count(),
|
||||
'ticket_order_count_today' => $activity['order_count'],
|
||||
'active_player_count_today' => $activity['player_count'],
|
||||
'latest_ticket_at' => $activity['latest_at'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{player_count: int, order_count: int, latest_at: ?string}
|
||||
*/
|
||||
private function todayTicketStats(string $siteCode, string $today): array
|
||||
{
|
||||
$base = DB::table('ticket_orders as o')
|
||||
->join('draws as d', 'd.id', '=', 'o.draw_id')
|
||||
->join('players as p', 'p.id', '=', 'o.player_id')
|
||||
->where('p.site_code', $siteCode)
|
||||
->whereDate('d.business_date', $today);
|
||||
|
||||
$latestAt = (clone $base)->max('o.created_at');
|
||||
|
||||
return [
|
||||
'player_count' => (int) (clone $base)->distinct('o.player_id')->count('o.player_id'),
|
||||
'order_count' => (int) (clone $base)->count(),
|
||||
'latest_at' => $latestAt !== null ? Carbon::parse((string) $latestAt)->toIso8601String() : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Models\AdminSite;
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\AgentNode;
|
||||
use App\Models\Player;
|
||||
@@ -27,7 +26,7 @@ final class SiteDashboardOverviewBuilder
|
||||
return null;
|
||||
}
|
||||
|
||||
$site = $this->resolvePrimarySite($admin);
|
||||
$site = SiteDashboardSiteResolver::resolvePrimarySite($admin);
|
||||
if ($site === null) {
|
||||
return null;
|
||||
}
|
||||
@@ -52,7 +51,11 @@ final class SiteDashboardOverviewBuilder
|
||||
$currencyCode = $this->reportQuery->resolvePeriodCurrencyCode($today, $today, $scoped)
|
||||
?? $this->reportQuery->resolvePeriodCurrencyCode($sevenDayFrom, $today, $scoped);
|
||||
$todayActivity = $this->todayActivityStats($siteCode, $today);
|
||||
$pendingBills = $this->pendingBillStats($siteId);
|
||||
$billStats = SiteSettlementBillStats::forSite($siteId);
|
||||
$pendingBills = [
|
||||
'count' => $billStats['pending_confirm_count'] + $billStats['payable_count'],
|
||||
'unpaid_minor' => $billStats['payable_unpaid_minor'],
|
||||
];
|
||||
$topAgentToday = $this->topAgentToday($scoped, $today);
|
||||
|
||||
return [
|
||||
@@ -78,18 +81,6 @@ final class SiteDashboardOverviewBuilder
|
||||
];
|
||||
}
|
||||
|
||||
private function resolvePrimarySite(AdminUser $admin): ?AdminSite
|
||||
{
|
||||
$siteIds = $admin->accessibleAdminSiteIds();
|
||||
if ($siteIds === null || $siteIds === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AdminSite::query()
|
||||
->where('id', (int) $siteIds[0])
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{player_count: int, order_count: int, latest_bet_at: ?string}
|
||||
*/
|
||||
@@ -110,22 +101,6 @@ final class SiteDashboardOverviewBuilder
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{count: int, unpaid_minor: int}
|
||||
*/
|
||||
private function pendingBillStats(int $siteId): array
|
||||
{
|
||||
$query = DB::table('settlement_bills as sb')
|
||||
->join('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id')
|
||||
->where('sp.admin_site_id', $siteId)
|
||||
->whereIn('sb.status', ['pending', 'pending_confirm', 'partial']);
|
||||
|
||||
return [
|
||||
'count' => (int) $query->count(),
|
||||
'unpaid_minor' => (int) $query->sum('sb.unpaid_amount'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
|
||||
22
app/Services/Admin/SiteDashboardSiteResolver.php
Normal file
22
app/Services/Admin/SiteDashboardSiteResolver.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Models\AdminSite;
|
||||
use App\Models\AdminUser;
|
||||
|
||||
/** 站点运营仪表盘:解析账号绑定的主接入站点。 */
|
||||
final class SiteDashboardSiteResolver
|
||||
{
|
||||
public static function resolvePrimarySite(AdminUser $admin): ?AdminSite
|
||||
{
|
||||
$siteIds = $admin->accessibleAdminSiteIds();
|
||||
if ($siteIds === null || $siteIds === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AdminSite::query()
|
||||
->where('id', (int) $siteIds[0])
|
||||
->first();
|
||||
}
|
||||
}
|
||||
92
app/Services/Admin/SiteFinanceDashboardOverviewBuilder.php
Normal file
92
app/Services/Admin/SiteFinanceDashboardOverviewBuilder.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\Player;
|
||||
use App\Models\TransferOrder;
|
||||
use App\Support\AdminAgentScope;
|
||||
use App\Support\AdminDataScope;
|
||||
use App\Support\AdminScopeContext;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
|
||||
/** 站点财务仪表盘:对账异常、待确认/待收付账单、钱包玩家规模。 */
|
||||
final class SiteFinanceDashboardOverviewBuilder
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function build(AdminUser $admin, AdminScopeContext $scope): ?array
|
||||
{
|
||||
if (! $admin->hasPermissionCode('dashboard.view')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$site = SiteDashboardSiteResolver::resolvePrimarySite($admin);
|
||||
if ($site === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$siteId = (int) $site->id;
|
||||
$siteCode = (string) $site->code;
|
||||
$billStats = SiteSettlementBillStats::forSite($siteId);
|
||||
$currencyCode = Player::query()
|
||||
->where('site_code', $siteCode)
|
||||
->whereNotNull('default_currency')
|
||||
->value('default_currency');
|
||||
|
||||
return [
|
||||
'admin_site_id' => $siteId,
|
||||
'site_code' => $siteCode,
|
||||
'site_name' => (string) $site->name,
|
||||
'wallet_player_count' => (int) Player::query()
|
||||
->where('site_code', $siteCode)
|
||||
->where('funding_mode', 'wallet')
|
||||
->count(),
|
||||
'credit_player_count' => (int) Player::query()
|
||||
->where('site_code', $siteCode)
|
||||
->where('funding_mode', 'credit')
|
||||
->count(),
|
||||
'pending_confirm_bill_count' => $billStats['pending_confirm_count'],
|
||||
'payable_bill_count' => $billStats['payable_count'],
|
||||
'payable_unpaid_minor' => $billStats['payable_unpaid_minor'],
|
||||
'pending_bill_count' => $billStats['pending_confirm_count'] + $billStats['payable_count'],
|
||||
'pending_unpaid_minor' => $billStats['payable_unpaid_minor'],
|
||||
'abnormal_transfer_count' => $this->abnormalTransferCount($admin, $scope),
|
||||
'currency_code' => is_string($currencyCode) && $currencyCode !== '' ? $currencyCode : null,
|
||||
];
|
||||
}
|
||||
|
||||
private function abnormalTransferCount(AdminUser $admin, AdminScopeContext $scope): int
|
||||
{
|
||||
$query = TransferOrder::query()
|
||||
->whereIn('status', ['processing', 'failed', 'pending_reconcile']);
|
||||
AdminDataScope::applyEloquentViaPlayer($query, $admin);
|
||||
$this->applyRequestedScopeViaPlayer($query, $scope);
|
||||
|
||||
return (int) $query->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EloquentBuilder<mixed> $query
|
||||
*/
|
||||
private function applyRequestedScopeViaPlayer(EloquentBuilder $query, AdminScopeContext $scope): void
|
||||
{
|
||||
$siteCode = $scope->effectiveRequestedSiteCode();
|
||||
$agentNodeId = $scope->effectiveRequestedAgentNodeId();
|
||||
if ($siteCode === null && $agentNodeId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$admin = $scope->admin;
|
||||
$query->whereHas('player', static function (EloquentBuilder $playerQuery) use ($admin, $siteCode, $agentNodeId): void {
|
||||
if ($siteCode !== null) {
|
||||
$playerQuery->where('site_code', $siteCode);
|
||||
}
|
||||
|
||||
if ($agentNodeId !== null) {
|
||||
AdminAgentScope::applyRequestedAgentNodeFilter($playerQuery, $admin, $agentNodeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
36
app/Services/Admin/SiteSettlementBillStats.php
Normal file
36
app/Services/Admin/SiteSettlementBillStats.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/** 站点信用账期账单摘要(待确认 / 待收付)。 */
|
||||
final class SiteSettlementBillStats
|
||||
{
|
||||
/**
|
||||
* @return array{
|
||||
* pending_confirm_count: int,
|
||||
* payable_count: int,
|
||||
* payable_unpaid_minor: int
|
||||
* }
|
||||
*/
|
||||
public static function forSite(int $siteId): array
|
||||
{
|
||||
$pendingConfirmQuery = DB::table('settlement_bills as sb')
|
||||
->join('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id')
|
||||
->where('sp.admin_site_id', $siteId)
|
||||
->where('sb.status', 'pending_confirm');
|
||||
|
||||
$payableQuery = DB::table('settlement_bills as sb')
|
||||
->join('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id')
|
||||
->where('sp.admin_site_id', $siteId)
|
||||
->whereIn('sb.status', ['confirmed', 'partial_paid', 'overdue'])
|
||||
->where('sb.unpaid_amount', '>', 0);
|
||||
|
||||
return [
|
||||
'pending_confirm_count' => (int) (clone $pendingConfirmQuery)->count(),
|
||||
'payable_count' => (int) (clone $payableQuery)->count(),
|
||||
'payable_unpaid_minor' => (int) (clone $payableQuery)->sum('sb.unpaid_amount'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ use App\Models\WalletTxn;
|
||||
use App\Models\TransferOrder;
|
||||
use App\Models\ReconcileJob;
|
||||
use App\Models\ReconcileItem;
|
||||
use App\Support\AdminScopeContext;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -56,6 +58,7 @@ final class WalletTransferReconcileDetector
|
||||
int $staleMinutes = 15,
|
||||
?int $playerId = null,
|
||||
bool $includeMainSiteCheck = true,
|
||||
?AdminScopeContext $scope = null,
|
||||
): array {
|
||||
$limit = max(1, $limit);
|
||||
$staleMinutes = max(1, $staleMinutes);
|
||||
@@ -77,6 +80,10 @@ final class WalletTransferReconcileDetector
|
||||
$query->where('player_id', $playerId);
|
||||
}
|
||||
|
||||
if ($scope !== null && ! $scope->isSuperAdmin()) {
|
||||
AdminScopePolicy::applyViaPlayer($query, $scope);
|
||||
}
|
||||
|
||||
$orders = $query->get();
|
||||
|
||||
if ($orders->isEmpty()) {
|
||||
@@ -118,13 +125,16 @@ final class WalletTransferReconcileDetector
|
||||
Carbon $periodStart,
|
||||
Carbon $periodEnd,
|
||||
?int $adminUserId,
|
||||
?int $adminSiteId = null,
|
||||
?int $playerId = null,
|
||||
): ReconcileJob {
|
||||
return DB::transaction(function () use ($items, $periodStart, $periodEnd, $adminUserId): ReconcileJob {
|
||||
return DB::transaction(function () use ($items, $periodStart, $periodEnd, $adminUserId, $adminSiteId, $playerId): ReconcileJob {
|
||||
$jobNo = 'REC'.now()->format('YmdHis').strtoupper(str_replace('-', '', Str::uuid()->toString()));
|
||||
|
||||
$job = ReconcileJob::query()->create([
|
||||
'job_no' => $jobNo,
|
||||
'admin_user_id' => $adminUserId,
|
||||
'admin_site_id' => $adminSiteId,
|
||||
'reconcile_type' => self::RECONCILE_TYPE,
|
||||
'status' => 'completed',
|
||||
'period_start' => $periodStart,
|
||||
@@ -132,6 +142,7 @@ final class WalletTransferReconcileDetector
|
||||
'summary_json' => [
|
||||
'item_count' => count($items),
|
||||
'mismatch_count' => count($items),
|
||||
'player_id' => $playerId,
|
||||
],
|
||||
'finished_at' => now(),
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user