|
|
|
|
@@ -2,7 +2,9 @@
|
|
|
|
|
|
|
|
|
|
namespace App\Services\Admin;
|
|
|
|
|
|
|
|
|
|
use App\Models\AdminUser;
|
|
|
|
|
use App\Models\AuditLog;
|
|
|
|
|
use App\Support\AdminDataScope;
|
|
|
|
|
use App\Models\Draw;
|
|
|
|
|
use App\Models\RiskPool;
|
|
|
|
|
use App\Models\RiskPoolLockLog;
|
|
|
|
|
@@ -109,9 +111,9 @@ final class AdminReportQueryService
|
|
|
|
|
* business_day_count: int
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
public function periodFinanceTotals(string $dateFrom, string $dateTo): array
|
|
|
|
|
public function periodFinanceTotals(string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$rows = $this->dailyProfitRows($dateFrom, $dateTo);
|
|
|
|
|
$rows = $this->dailyProfitRows($dateFrom, $dateTo, $scopedAdmin);
|
|
|
|
|
$totalBet = 0;
|
|
|
|
|
$totalPayout = 0;
|
|
|
|
|
$totalGross = 0;
|
|
|
|
|
@@ -121,9 +123,11 @@ final class AdminReportQueryService
|
|
|
|
|
$totalGross += (int) $row['approx_house_gross_minor'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$activity = DB::table('draws as d')
|
|
|
|
|
$activityQuery = DB::table('draws as d')
|
|
|
|
|
->join('ticket_orders as o', 'o.draw_id', '=', 'd.id')
|
|
|
|
|
->whereBetween('d.business_date', [$dateFrom, $dateTo])
|
|
|
|
|
->whereBetween('d.business_date', [$dateFrom, $dateTo]);
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($activityQuery, $scopedAdmin, 'o');
|
|
|
|
|
$activity = $activityQuery
|
|
|
|
|
->selectRaw('COUNT(DISTINCT d.id) as draw_count')
|
|
|
|
|
->selectRaw('COUNT(DISTINCT d.business_date) as business_day_count')
|
|
|
|
|
->first();
|
|
|
|
|
@@ -142,7 +146,7 @@ final class AdminReportQueryService
|
|
|
|
|
*
|
|
|
|
|
* @return list<array<string, mixed>>
|
|
|
|
|
*/
|
|
|
|
|
public function dailyProfitSeriesFilled(string $dateFrom, string $dateTo, int $maxDays = 90): array
|
|
|
|
|
public function dailyProfitSeriesFilled(string $dateFrom, string $dateTo, int $maxDays = 90, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$from = Carbon::parse($dateFrom)->startOfDay();
|
|
|
|
|
$to = Carbon::parse($dateTo)->startOfDay();
|
|
|
|
|
@@ -156,7 +160,7 @@ final class AdminReportQueryService
|
|
|
|
|
$truncated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$indexed = collect($this->dailyProfitRows($chartFrom, $chartTo))->keyBy('business_date');
|
|
|
|
|
$indexed = collect($this->dailyProfitRows($chartFrom, $chartTo, $scopedAdmin))->keyBy('business_date');
|
|
|
|
|
$cursor = Carbon::parse($chartFrom)->startOfDay();
|
|
|
|
|
$end = Carbon::parse($chartTo)->startOfDay();
|
|
|
|
|
$series = [];
|
|
|
|
|
@@ -189,8 +193,9 @@ final class AdminReportQueryService
|
|
|
|
|
string $dateTo,
|
|
|
|
|
?string $playCode = null,
|
|
|
|
|
int $limit = 12,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
): array {
|
|
|
|
|
return $this->playDimensionBaseQuery($playCode, $dateFrom, $dateTo)
|
|
|
|
|
return $this->playDimensionBaseQuery($playCode, $dateFrom, $dateTo, $scopedAdmin)
|
|
|
|
|
->orderByDesc('total_bet_minor')
|
|
|
|
|
->limit($limit)
|
|
|
|
|
->get()
|
|
|
|
|
@@ -207,20 +212,78 @@ final class AdminReportQueryService
|
|
|
|
|
->all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function resolvePeriodCurrencyCode(string $dateFrom, string $dateTo): ?string
|
|
|
|
|
/**
|
|
|
|
|
* 仪表盘「代理排行」:按代理子树聚合投注/派彩/盈亏(与 daily-profit 同口径)。
|
|
|
|
|
*
|
|
|
|
|
* @return list<array{
|
|
|
|
|
* agent_node_id: int,
|
|
|
|
|
* agent_code: string,
|
|
|
|
|
* agent_name: string,
|
|
|
|
|
* total_bet_minor: int,
|
|
|
|
|
* total_payout_minor: int,
|
|
|
|
|
* approx_house_gross_minor: int
|
|
|
|
|
* }>
|
|
|
|
|
*/
|
|
|
|
|
public function agentRankingRows(
|
|
|
|
|
string $dateFrom,
|
|
|
|
|
string $dateTo,
|
|
|
|
|
?string $playCode = null,
|
|
|
|
|
int $limit = 200,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
): array {
|
|
|
|
|
$query = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
|
|
|
|
->leftJoin('players as p', 'p.id', '=', 'ti.player_id')
|
|
|
|
|
->leftJoin('agent_nodes as an', 'an.id', '=', 'p.agent_node_id')
|
|
|
|
|
->selectRaw('p.agent_node_id as agent_node_id')
|
|
|
|
|
->selectRaw('an.code as agent_code')
|
|
|
|
|
->selectRaw('an.name as agent_name')
|
|
|
|
|
->selectRaw('SUM(ti.actual_deduct_amount) as total_bet_minor')
|
|
|
|
|
->selectRaw('SUM(ti.win_amount + ti.jackpot_win_amount) as total_payout_minor')
|
|
|
|
|
->selectRaw('SUM(ti.actual_deduct_amount) - SUM(ti.win_amount + ti.jackpot_win_amount) as approx_house_gross_minor')
|
|
|
|
|
->whereDate('o.created_at', '>=', $dateFrom)
|
|
|
|
|
->whereDate('o.created_at', '<=', $dateTo)
|
|
|
|
|
->whereNotNull('p.agent_node_id')
|
|
|
|
|
->groupBy('p.agent_node_id', 'an.code', 'an.name');
|
|
|
|
|
|
|
|
|
|
if ($playCode !== null && $playCode !== '') {
|
|
|
|
|
$query->where('ti.play_code', $playCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AdminDataScope::applyToPlayersAlias($query, $scopedAdmin, 'p');
|
|
|
|
|
|
|
|
|
|
return $query
|
|
|
|
|
->orderByDesc('total_bet_minor')
|
|
|
|
|
->limit($limit)
|
|
|
|
|
->get()
|
|
|
|
|
->map(static function (object $row): array {
|
|
|
|
|
return [
|
|
|
|
|
'agent_node_id' => (int) $row->agent_node_id,
|
|
|
|
|
'agent_code' => (string) ($row->agent_code ?? ''),
|
|
|
|
|
'agent_name' => (string) ($row->agent_name ?? ''),
|
|
|
|
|
'total_bet_minor' => (int) $row->total_bet_minor,
|
|
|
|
|
'total_payout_minor' => (int) $row->total_payout_minor,
|
|
|
|
|
'approx_house_gross_minor' => (int) $row->approx_house_gross_minor,
|
|
|
|
|
];
|
|
|
|
|
})
|
|
|
|
|
->values()
|
|
|
|
|
->all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function resolvePeriodCurrencyCode(string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): ?string
|
|
|
|
|
{
|
|
|
|
|
$currencyCode = (string) (DB::table('ticket_orders as o')
|
|
|
|
|
$currencyQuery = DB::table('ticket_orders as o')
|
|
|
|
|
->join('draws as d', 'd.id', '=', 'o.draw_id')
|
|
|
|
|
->whereBetween('d.business_date', [$dateFrom, $dateTo])
|
|
|
|
|
->orderByDesc('o.id')
|
|
|
|
|
->value('o.currency_code') ?? '');
|
|
|
|
|
->whereBetween('d.business_date', [$dateFrom, $dateTo]);
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($currencyQuery, $scopedAdmin, 'o');
|
|
|
|
|
$currencyCode = (string) ($currencyQuery->orderByDesc('o.id')->value('o.currency_code') ?? '');
|
|
|
|
|
|
|
|
|
|
return $currencyCode !== '' ? $currencyCode : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function dailyProfitPaginated(string $dateFrom, string $dateTo, int $page, int $perPage): LengthAwarePaginator
|
|
|
|
|
public function dailyProfitPaginated(string $dateFrom, string $dateTo, int $page, int $perPage, ?AdminUser $scopedAdmin = null): LengthAwarePaginator
|
|
|
|
|
{
|
|
|
|
|
$rows = $this->dailyProfitRows($dateFrom, $dateTo);
|
|
|
|
|
$rows = $this->dailyProfitRows($dateFrom, $dateTo, $scopedAdmin);
|
|
|
|
|
$total = count($rows);
|
|
|
|
|
$offset = max(0, ($page - 1) * $perPage);
|
|
|
|
|
$items = array_slice($rows, $offset, $perPage);
|
|
|
|
|
@@ -233,14 +296,18 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<string, mixed>>
|
|
|
|
|
*/
|
|
|
|
|
public function dailyProfitRows(string $dateFrom, string $dateTo): array
|
|
|
|
|
public function dailyProfitRows(string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$betSub = DB::table('ticket_orders')
|
|
|
|
|
->selectRaw('draw_id, SUM(total_actual_deduct) as total_bet_minor')
|
|
|
|
|
->groupBy('draw_id');
|
|
|
|
|
$payoutSub = DB::table('ticket_items')
|
|
|
|
|
->selectRaw('draw_id, SUM(win_amount + jackpot_win_amount) as total_payout_minor')
|
|
|
|
|
->groupBy('draw_id');
|
|
|
|
|
$betSub = DB::table('ticket_orders as o')
|
|
|
|
|
->selectRaw('o.draw_id, SUM(o.total_actual_deduct) as total_bet_minor')
|
|
|
|
|
->groupBy('o.draw_id');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($betSub, $scopedAdmin, 'o');
|
|
|
|
|
|
|
|
|
|
$payoutSub = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
|
|
|
|
->selectRaw('ti.draw_id, SUM(ti.win_amount + ti.jackpot_win_amount) as total_payout_minor')
|
|
|
|
|
->groupBy('ti.draw_id');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($payoutSub, $scopedAdmin, 'o');
|
|
|
|
|
|
|
|
|
|
return DB::table('draws as d')
|
|
|
|
|
->whereBetween('d.business_date', [$dateFrom, $dateTo])
|
|
|
|
|
@@ -284,19 +351,26 @@ final class AdminReportQueryService
|
|
|
|
|
* date_to: ?string
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
public function platformLifetimeTotals(): array
|
|
|
|
|
public function platformLifetimeTotals(?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$totalBetMinor = (int) DB::table('ticket_orders')->sum('total_actual_deduct');
|
|
|
|
|
$betQuery = DB::table('ticket_orders as o');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($betQuery, $scopedAdmin, 'o');
|
|
|
|
|
$totalBetMinor = (int) $betQuery->sum('o.total_actual_deduct');
|
|
|
|
|
|
|
|
|
|
$payoutAgg = DB::table('ticket_items')
|
|
|
|
|
->selectRaw('COALESCE(SUM(win_amount), 0) as win_minor, COALESCE(SUM(jackpot_win_amount), 0) as jackpot_minor')
|
|
|
|
|
$payoutQuery = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($payoutQuery, $scopedAdmin, 'o');
|
|
|
|
|
$payoutAgg = $payoutQuery
|
|
|
|
|
->selectRaw('COALESCE(SUM(ti.win_amount), 0) as win_minor, COALESCE(SUM(ti.jackpot_win_amount), 0) as jackpot_minor')
|
|
|
|
|
->first();
|
|
|
|
|
$totalWinMinor = (int) ($payoutAgg->win_minor ?? 0);
|
|
|
|
|
$totalJackpotMinor = (int) ($payoutAgg->jackpot_minor ?? 0);
|
|
|
|
|
$totalPayoutMinor = $totalWinMinor + $totalJackpotMinor;
|
|
|
|
|
|
|
|
|
|
$activity = DB::table('draws as d')
|
|
|
|
|
->join('ticket_orders as o', 'o.draw_id', '=', 'd.id')
|
|
|
|
|
$activityQuery = DB::table('draws as d')
|
|
|
|
|
->join('ticket_orders as o', 'o.draw_id', '=', 'd.id');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($activityQuery, $scopedAdmin, 'o');
|
|
|
|
|
$activity = $activityQuery
|
|
|
|
|
->selectRaw('COUNT(DISTINCT d.id) as draw_count')
|
|
|
|
|
->selectRaw('COUNT(DISTINCT d.business_date) as business_day_count')
|
|
|
|
|
->selectRaw('MIN(d.business_date) as date_from')
|
|
|
|
|
@@ -309,7 +383,15 @@ final class AdminReportQueryService
|
|
|
|
|
$dateFrom = $this->formatBusinessDateValue($activity?->date_from);
|
|
|
|
|
$dateTo = $this->formatBusinessDateValue($activity?->date_to);
|
|
|
|
|
|
|
|
|
|
$currencyCode = (string) (DB::table('ticket_orders')->orderByDesc('id')->value('currency_code') ?? '');
|
|
|
|
|
$currencyQuery = DB::table('ticket_orders as o');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($currencyQuery, $scopedAdmin, 'o');
|
|
|
|
|
$currencyCode = (string) ($currencyQuery->orderByDesc('o.id')->value('o.currency_code') ?? '');
|
|
|
|
|
|
|
|
|
|
$orderCountQuery = DB::table('ticket_orders as o');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($orderCountQuery, $scopedAdmin, 'o');
|
|
|
|
|
$itemCountQuery = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id');
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($itemCountQuery, $scopedAdmin, 'o');
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'currency_code' => $currencyCode !== '' ? $currencyCode : null,
|
|
|
|
|
@@ -318,8 +400,8 @@ final class AdminReportQueryService
|
|
|
|
|
'total_jackpot_minor' => $totalJackpotMinor,
|
|
|
|
|
'total_payout_minor' => $totalPayoutMinor,
|
|
|
|
|
'approx_house_gross_minor' => $totalBetMinor - $totalPayoutMinor,
|
|
|
|
|
'order_count' => (int) DB::table('ticket_orders')->count(),
|
|
|
|
|
'ticket_item_count' => (int) DB::table('ticket_items')->count(),
|
|
|
|
|
'order_count' => (int) $orderCountQuery->count(),
|
|
|
|
|
'ticket_item_count' => (int) $itemCountQuery->count('ti.id'),
|
|
|
|
|
'draw_count' => $drawCount,
|
|
|
|
|
'business_day_count' => $businessDayCount,
|
|
|
|
|
'date_from' => $dateFrom,
|
|
|
|
|
@@ -333,8 +415,10 @@ final class AdminReportQueryService
|
|
|
|
|
string $dateTo,
|
|
|
|
|
int $page,
|
|
|
|
|
int $perPage,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
?int $requestedAgentNodeId = null,
|
|
|
|
|
): LengthAwarePaginator {
|
|
|
|
|
$query = $this->playerWinLossBaseQuery($playerId, $dateFrom, $dateTo);
|
|
|
|
|
$query = $this->playerWinLossBaseQuery($playerId, $dateFrom, $dateTo, $scopedAdmin, $requestedAgentNodeId);
|
|
|
|
|
|
|
|
|
|
return $query->paginate($perPage, ['*'], 'page', $page);
|
|
|
|
|
}
|
|
|
|
|
@@ -345,8 +429,9 @@ final class AdminReportQueryService
|
|
|
|
|
string $dateTo,
|
|
|
|
|
int $page,
|
|
|
|
|
int $perPage,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
): LengthAwarePaginator {
|
|
|
|
|
$query = $this->playDimensionBaseQuery($playCode, $dateFrom, $dateTo);
|
|
|
|
|
$query = $this->playDimensionBaseQuery($playCode, $dateFrom, $dateTo, $scopedAdmin);
|
|
|
|
|
|
|
|
|
|
return $query->paginate($perPage, ['*'], 'page', $page);
|
|
|
|
|
}
|
|
|
|
|
@@ -357,8 +442,9 @@ final class AdminReportQueryService
|
|
|
|
|
string $dateTo,
|
|
|
|
|
int $page,
|
|
|
|
|
int $perPage,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
): LengthAwarePaginator {
|
|
|
|
|
$query = $this->rebateCommissionBaseQuery($playCode, $dateFrom, $dateTo);
|
|
|
|
|
$query = $this->rebateCommissionBaseQuery($playCode, $dateFrom, $dateTo, $scopedAdmin);
|
|
|
|
|
|
|
|
|
|
return $query->paginate($perPage, ['*'], 'page', $page);
|
|
|
|
|
}
|
|
|
|
|
@@ -366,21 +452,21 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
public function reportRows(string $reportType, ?array $filterJson): array
|
|
|
|
|
public function reportRows(string $reportType, ?array $filterJson, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$range = $this->resolveDateRange($filterJson);
|
|
|
|
|
$dateFrom = $range['date_from'];
|
|
|
|
|
$dateTo = $range['date_to'];
|
|
|
|
|
|
|
|
|
|
return match ($reportType) {
|
|
|
|
|
'draw_profit_summary' => $this->drawProfitExportRows($filterJson),
|
|
|
|
|
'daily_profit_summary' => $this->dailyProfitExportRows($dateFrom, $dateTo),
|
|
|
|
|
'player_win_loss' => $this->playerWinLossExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'play_dimension_report' => $this->playDimensionExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'rebate_commission_report' => $this->rebateCommissionExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'draw_profit_summary' => $this->drawProfitExportRows($filterJson, $scopedAdmin),
|
|
|
|
|
'daily_profit_summary' => $this->dailyProfitExportRows($dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'player_win_loss' => $this->playerWinLossExportRows($filterJson, $dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'play_dimension_report' => $this->playDimensionExportRows($filterJson, $dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'rebate_commission_report' => $this->rebateCommissionExportRows($filterJson, $dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'audit_operation_report' => $this->auditExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'wallet_transfer_report', 'transfer_orders_daily' => $this->transferOrdersExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'wallet_txns_daily' => $this->walletTxnsExportRows($filterJson, $dateFrom, $dateTo),
|
|
|
|
|
'wallet_transfer_report', 'transfer_orders_daily' => $this->transferOrdersExportRows($filterJson, $dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'wallet_txns_daily' => $this->walletTxnsExportRows($filterJson, $dateFrom, $dateTo, $scopedAdmin),
|
|
|
|
|
'hot_number_risk_report' => $this->hotNumberRiskExportRows($filterJson),
|
|
|
|
|
'sold_out_number_report' => $this->soldOutNumberExportRows($filterJson),
|
|
|
|
|
default => [
|
|
|
|
|
@@ -427,12 +513,12 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function dailyProfitExportRows(string $dateFrom, string $dateTo): array
|
|
|
|
|
private function dailyProfitExportRows(string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$rows = [
|
|
|
|
|
['日期', '下注', '派彩', '盈亏'],
|
|
|
|
|
];
|
|
|
|
|
foreach ($this->dailyProfitRows($dateFrom, $dateTo) as $row) {
|
|
|
|
|
foreach ($this->dailyProfitRows($dateFrom, $dateTo, $scopedAdmin) as $row) {
|
|
|
|
|
$rows[] = [
|
|
|
|
|
$row['business_date'],
|
|
|
|
|
$row['total_bet_minor'],
|
|
|
|
|
@@ -447,13 +533,13 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function playerWinLossExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
|
|
|
|
|
private function playerWinLossExportRows(?array $filterJson, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$playerId = isset($filterJson['player_id']) ? (int) $filterJson['player_id'] : null;
|
|
|
|
|
$rows = [
|
|
|
|
|
['玩家ID', '用户名', '下注', '派彩', '净输赢'],
|
|
|
|
|
];
|
|
|
|
|
$items = $this->playerWinLossBaseQuery($playerId, $dateFrom, $dateTo)->get();
|
|
|
|
|
$items = $this->playerWinLossBaseQuery($playerId, $dateFrom, $dateTo, $scopedAdmin)->get();
|
|
|
|
|
foreach ($items as $row) {
|
|
|
|
|
$rows[] = [
|
|
|
|
|
(int) $row->player_id,
|
|
|
|
|
@@ -470,13 +556,13 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function playDimensionExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
|
|
|
|
|
private function playDimensionExportRows(?array $filterJson, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$playCode = isset($filterJson['play_code']) ? trim((string) $filterJson['play_code']) : null;
|
|
|
|
|
$rows = [
|
|
|
|
|
['玩法', '维度', '下注', '派彩', '盈亏'],
|
|
|
|
|
];
|
|
|
|
|
$items = $this->playDimensionBaseQuery($playCode !== '' ? $playCode : null, $dateFrom, $dateTo)->get();
|
|
|
|
|
$items = $this->playDimensionBaseQuery($playCode !== '' ? $playCode : null, $dateFrom, $dateTo, $scopedAdmin)->get();
|
|
|
|
|
foreach ($items as $row) {
|
|
|
|
|
$rows[] = [
|
|
|
|
|
(string) $row->play_code,
|
|
|
|
|
@@ -493,13 +579,13 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function rebateCommissionExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
|
|
|
|
|
private function rebateCommissionExportRows(?array $filterJson, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$playCode = isset($filterJson['play_code']) ? trim((string) $filterJson['play_code']) : null;
|
|
|
|
|
$rows = [
|
|
|
|
|
['玩法', '回水', '订单数', '注单数'],
|
|
|
|
|
];
|
|
|
|
|
$items = $this->rebateCommissionBaseQuery($playCode !== '' ? $playCode : null, $dateFrom, $dateTo)->get();
|
|
|
|
|
$items = $this->rebateCommissionBaseQuery($playCode !== '' ? $playCode : null, $dateFrom, $dateTo, $scopedAdmin)->get();
|
|
|
|
|
foreach ($items as $row) {
|
|
|
|
|
$rows[] = [
|
|
|
|
|
(string) $row->play_code,
|
|
|
|
|
@@ -545,30 +631,43 @@ final class AdminReportQueryService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return \Illuminate\Database\Query\Builder */
|
|
|
|
|
private function playerWinLossBaseQuery(?int $playerId, string $dateFrom, string $dateTo)
|
|
|
|
|
{
|
|
|
|
|
private function playerWinLossBaseQuery(
|
|
|
|
|
?int $playerId,
|
|
|
|
|
string $dateFrom,
|
|
|
|
|
string $dateTo,
|
|
|
|
|
?AdminUser $scopedAdmin = null,
|
|
|
|
|
?int $requestedAgentNodeId = null,
|
|
|
|
|
) {
|
|
|
|
|
$query = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
|
|
|
|
->leftJoin('players as p', 'p.id', '=', 'ti.player_id')
|
|
|
|
|
->leftJoin('agent_nodes as an', 'an.id', '=', 'p.agent_node_id')
|
|
|
|
|
->selectRaw('ti.player_id')
|
|
|
|
|
->selectRaw('p.username as username')
|
|
|
|
|
->selectRaw('p.agent_node_id as agent_node_id')
|
|
|
|
|
->selectRaw('an.code as agent_code')
|
|
|
|
|
->selectRaw('an.name as agent_name')
|
|
|
|
|
->selectRaw('SUM(ti.actual_deduct_amount) as total_bet_minor')
|
|
|
|
|
->selectRaw('SUM(ti.win_amount + ti.jackpot_win_amount) as total_payout_minor')
|
|
|
|
|
->selectRaw('SUM(ti.actual_deduct_amount) - SUM(ti.win_amount + ti.jackpot_win_amount) as net_win_loss_minor')
|
|
|
|
|
->whereDate('o.created_at', '>=', $dateFrom)
|
|
|
|
|
->whereDate('o.created_at', '<=', $dateTo)
|
|
|
|
|
->groupBy('ti.player_id', 'p.username')
|
|
|
|
|
->groupBy('ti.player_id', 'p.username', 'p.agent_node_id', 'an.code', 'an.name')
|
|
|
|
|
->orderByDesc('net_win_loss_minor');
|
|
|
|
|
|
|
|
|
|
if ($playerId !== null && $playerId > 0) {
|
|
|
|
|
$query->where('ti.player_id', $playerId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($scopedAdmin !== null) {
|
|
|
|
|
AdminDataScope::applyToPlayersAlias($query, $scopedAdmin, 'p', $requestedAgentNodeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return \Illuminate\Database\Query\Builder */
|
|
|
|
|
private function playDimensionBaseQuery(?string $playCode, string $dateFrom, string $dateTo)
|
|
|
|
|
private function playDimensionBaseQuery(?string $playCode, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null)
|
|
|
|
|
{
|
|
|
|
|
$query = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
|
|
|
|
@@ -587,11 +686,13 @@ final class AdminReportQueryService
|
|
|
|
|
$query->where('ti.play_code', $playCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($query, $scopedAdmin, 'o');
|
|
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return \Illuminate\Database\Query\Builder */
|
|
|
|
|
private function rebateCommissionBaseQuery(?string $playCode, string $dateFrom, string $dateTo)
|
|
|
|
|
private function rebateCommissionBaseQuery(?string $playCode, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null)
|
|
|
|
|
{
|
|
|
|
|
$query = DB::table('ticket_items as ti')
|
|
|
|
|
->join('ticket_orders as o', 'o.id', '=', 'ti.order_id')
|
|
|
|
|
@@ -608,13 +709,15 @@ final class AdminReportQueryService
|
|
|
|
|
$query->where('ti.play_code', $playCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AdminDataScope::applyToTicketOrdersViaPlayer($query, $scopedAdmin, 'o');
|
|
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function drawProfitExportRows(?array $filterJson): array
|
|
|
|
|
private function drawProfitExportRows(?array $filterJson, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$draw = $this->resolveDrawForReport($filterJson);
|
|
|
|
|
if ($draw === null) {
|
|
|
|
|
@@ -622,12 +725,19 @@ final class AdminReportQueryService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$drawId = (int) $draw->id;
|
|
|
|
|
$totalBetMinor = (int) TicketOrder::query()->where('draw_id', $drawId)->sum('total_actual_deduct');
|
|
|
|
|
$orderCount = (int) TicketOrder::query()->where('draw_id', $drawId)->count();
|
|
|
|
|
$itemCount = (int) TicketItem::query()->where('draw_id', $drawId)->count();
|
|
|
|
|
$currencyCode = (string) (TicketOrder::query()->where('draw_id', $drawId)->value('currency_code') ?? '');
|
|
|
|
|
$totalWinMinor = (int) TicketItem::query()->where('draw_id', $drawId)->sum('win_amount');
|
|
|
|
|
$totalJackpotWinMinor = (int) TicketItem::query()->where('draw_id', $drawId)->sum('jackpot_win_amount');
|
|
|
|
|
$orderQuery = TicketOrder::query()->where('draw_id', $drawId);
|
|
|
|
|
$itemQuery = TicketItem::query()->where('draw_id', $drawId);
|
|
|
|
|
if ($scopedAdmin !== null) {
|
|
|
|
|
AdminDataScope::applyEloquentViaPlayer($orderQuery, $scopedAdmin);
|
|
|
|
|
AdminDataScope::applyEloquentViaPlayer($itemQuery, $scopedAdmin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$totalBetMinor = (int) $orderQuery->sum('total_actual_deduct');
|
|
|
|
|
$orderCount = (int) $orderQuery->count();
|
|
|
|
|
$itemCount = (int) $itemQuery->count();
|
|
|
|
|
$currencyCode = (string) ((clone $orderQuery)->value('currency_code') ?? '');
|
|
|
|
|
$totalWinMinor = (int) $itemQuery->sum('win_amount');
|
|
|
|
|
$totalJackpotWinMinor = (int) (clone $itemQuery)->sum('jackpot_win_amount');
|
|
|
|
|
$totalPayoutMinor = $totalWinMinor + $totalJackpotWinMinor;
|
|
|
|
|
$approxHouseGrossMinor = $totalBetMinor - $totalPayoutMinor;
|
|
|
|
|
|
|
|
|
|
@@ -842,7 +952,7 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function transferOrdersExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
|
|
|
|
|
private function transferOrdersExportRows(?array $filterJson, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$rows = [
|
|
|
|
|
['转账单号', '玩家ID', '用户名', '昵称', '方向', '币种', '金额', '状态', '外部单号', '失败原因', '创建时间', '完成时间'],
|
|
|
|
|
@@ -852,6 +962,10 @@ final class AdminReportQueryService
|
|
|
|
|
->with(['player:id,username,nickname'])
|
|
|
|
|
->orderByDesc('id');
|
|
|
|
|
|
|
|
|
|
if ($scopedAdmin !== null) {
|
|
|
|
|
AdminDataScope::applyEloquentViaPlayer($query, $scopedAdmin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$playerId = isset($filterJson['player_id']) ? (int) $filterJson['player_id'] : null;
|
|
|
|
|
if ($playerId !== null && $playerId > 0) {
|
|
|
|
|
$query->where('player_id', $playerId);
|
|
|
|
|
@@ -884,7 +998,7 @@ final class AdminReportQueryService
|
|
|
|
|
/**
|
|
|
|
|
* @return list<array<int, string|int|float|null>>
|
|
|
|
|
*/
|
|
|
|
|
private function walletTxnsExportRows(?array $filterJson, string $dateFrom, string $dateTo): array
|
|
|
|
|
private function walletTxnsExportRows(?array $filterJson, string $dateFrom, string $dateTo, ?AdminUser $scopedAdmin = null): array
|
|
|
|
|
{
|
|
|
|
|
$rows = [
|
|
|
|
|
['流水号', '玩家ID', '用户名', '业务类型', '业务单号', '方向', '金额', '变动前余额', '变动后余额', '状态', '外部单号', '备注', '创建时间'],
|
|
|
|
|
@@ -894,6 +1008,10 @@ final class AdminReportQueryService
|
|
|
|
|
->with(['player:id,username'])
|
|
|
|
|
->orderByDesc('id');
|
|
|
|
|
|
|
|
|
|
if ($scopedAdmin !== null) {
|
|
|
|
|
AdminDataScope::applyEloquentViaPlayer($query, $scopedAdmin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$playerId = isset($filterJson['player_id']) ? (int) $filterJson['player_id'] : null;
|
|
|
|
|
if ($playerId !== null && $playerId > 0) {
|
|
|
|
|
$query->where('player_id', $playerId);
|
|
|
|
|
|