feat: 增强代理结算和账单管理功能
- 在多个控制器中引入 SettlementPartyEnrichment 服务,以优化代理结算和账单的处理逻辑。 - 更新 AgentSettlementBillIndexController 和 AgentSettlementBillShowController,支持根据账单 ID 和关键字进行查询。 - 在 AgentSettlementPeriodCloseController 中添加对站点管理权限的验证,确保只有具备相应权限的管理员能够关闭账期。 - 在 AgentSettlementPeriodIndexController 中更新账期数据的返回格式,提升数据的完整性和可用性。 - 引入对相对占成比例的支持,增强代理资料的管理能力,确保数据一致性。
This commit is contained in:
@@ -48,13 +48,9 @@ final class AdminCreditLedgerIndexController extends Controller
|
||||
$perPage = $this->perPage($request, 'per_page', 20, 100);
|
||||
$page = $this->page($request);
|
||||
|
||||
$result = $this->ledgerService->listUnified(
|
||||
$admin,
|
||||
$siteCode,
|
||||
$page,
|
||||
$perPage,
|
||||
$filters,
|
||||
);
|
||||
$result = $filters->betFlowDisplaySimple
|
||||
? $this->ledgerService->listBetFlowSimplified($admin, $siteCode, $page, $perPage, $filters)
|
||||
: $this->ledgerService->listUnified($admin, $siteCode, $page, $perPage, $filters);
|
||||
|
||||
return ApiResponse::success($result);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
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;
|
||||
@@ -12,6 +14,12 @@ 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();
|
||||
@@ -38,6 +46,11 @@ final class AgentSettlementBillIndexController extends Controller
|
||||
$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);
|
||||
@@ -54,16 +67,78 @@ final class AgentSettlementBillIndexController extends Controller
|
||||
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 = $query->limit(200)->get();
|
||||
$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>>
|
||||
@@ -90,34 +165,57 @@ final class AgentSettlementBillIndexController extends Controller
|
||||
$players = $playerIds !== []
|
||||
? DB::table('players')
|
||||
->whereIn('id', array_unique($playerIds))
|
||||
->select(['id', 'username', 'site_player_id', 'funding_mode', 'auth_source'])
|
||||
->select(['id', 'username', 'site_player_id', 'agent_node_id', 'funding_mode', 'auth_source'])
|
||||
->get()
|
||||
->keyBy('id')
|
||||
: collect();
|
||||
$agents = $agentIds !== []
|
||||
? DB::table('agent_nodes')->whereIn('id', array_unique($agentIds))->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;
|
||||
$item['owner_label'] = $this->resolvePartyLabel(
|
||||
(string) $row->owner_type,
|
||||
(int) $row->owner_id,
|
||||
$players,
|
||||
$agents,
|
||||
);
|
||||
$item['counterparty_label'] = $this->resolvePartyLabel(
|
||||
(string) $row->counterparty_type,
|
||||
(int) $row->counterparty_id,
|
||||
$players,
|
||||
$agents,
|
||||
);
|
||||
if ((string) $row->owner_type === 'player') {
|
||||
$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;
|
||||
}
|
||||
|
||||
@@ -128,30 +226,22 @@ final class AgentSettlementBillIndexController extends Controller
|
||||
* @param Collection<int, object> $players
|
||||
* @param Collection<int, object> $agents
|
||||
*/
|
||||
private function resolvePartyLabel(
|
||||
private function legacyOwnerLabel(
|
||||
string $type,
|
||||
int $id,
|
||||
Collection $players,
|
||||
Collection $agents,
|
||||
): string {
|
||||
if ($type === 'platform' || $id <= 0) {
|
||||
return 'platform';
|
||||
}
|
||||
|
||||
if ($type === 'player') {
|
||||
$player = $players->get($id);
|
||||
|
||||
return $player !== null
|
||||
? (string) ($player->username ?: $player->site_player_id)
|
||||
? (string) ($player->username ?: $player->site_player_id ?: "player#{$id}")
|
||||
: "player#{$id}";
|
||||
}
|
||||
|
||||
if ($type === 'agent') {
|
||||
$agent = $agents->get($id);
|
||||
|
||||
return $agent !== null
|
||||
? (string) ($agent->name ?: $agent->code)
|
||||
: "agent#{$id}";
|
||||
return $this->partyEnrichment->formatAgent($agents->get($id), $id);
|
||||
}
|
||||
|
||||
return "{$type}#{$id}";
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
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 Illuminate\Http\JsonResponse;
|
||||
@@ -11,6 +12,10 @@ use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class AgentSettlementBillShowController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SettlementPartyEnrichment $partyEnrichment,
|
||||
) {}
|
||||
|
||||
public function __invoke(Request $request, int $settlement_bill): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
@@ -30,6 +35,35 @@ final class AgentSettlementBillShowController extends Controller
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
$agentIds = $rebateAllocations
|
||||
->filter(static fn (object $row): bool => (string) $row->participant_type === 'agent')
|
||||
->pluck('participant_id')
|
||||
->map(static fn ($id): int => (int) $id)
|
||||
->filter(static fn (int $id): bool => $id > 0)
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
$agents = $this->partyEnrichment->loadAgents($agentIds);
|
||||
$rebateAllocations = $rebateAllocations
|
||||
->map(function (object $row) use ($agents): array {
|
||||
$type = (string) $row->participant_type;
|
||||
$id = (int) $row->participant_id;
|
||||
|
||||
return [
|
||||
'id' => (int) $row->id,
|
||||
'rebate_record_id' => (int) $row->rebate_record_id,
|
||||
'settlement_bill_id' => (int) $row->settlement_bill_id,
|
||||
'participant_type' => $type,
|
||||
'participant_id' => $id,
|
||||
'participant_label' => $this->partyEnrichment->formatCounterpartyLabel($type, $id, $agents),
|
||||
'actual_share_rate' => (float) $row->actual_share_rate,
|
||||
'allocated_amount' => (int) $row->allocated_amount,
|
||||
'allocation_rule' => (string) $row->allocation_rule,
|
||||
];
|
||||
})
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$adjustments = DB::table('settlement_adjustments')
|
||||
->where('original_bill_id', $settlement_bill)
|
||||
->orderByDesc('id')
|
||||
|
||||
@@ -22,6 +22,7 @@ final class AgentSettlementPeriodCloseController extends Controller
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
abort_if(! AdminAgentSettlementScope::periodAccessible($admin, $settlement_period), 404);
|
||||
AdminAgentSettlementScope::assertCanManageSitePeriods($admin);
|
||||
|
||||
$before = DB::table('settlement_periods')->where('id', $settlement_period)->first();
|
||||
$result = $service->closePeriod($settlement_period);
|
||||
|
||||
@@ -30,7 +30,7 @@ final class AgentSettlementPeriodIndexController extends Controller
|
||||
$periods = $query->limit(100)->get();
|
||||
|
||||
return ApiResponse::success([
|
||||
'items' => $summaryService->attachToPeriodRows($periods),
|
||||
'items' => $summaryService->attachToPeriodRows($periods, $admin),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,17 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Middleware\RecordAdminApiAudit;
|
||||
use App\Http\Requests\Admin\AdminSettlementPeriodStoreRequest;
|
||||
use App\Services\AuditLogger;
|
||||
use App\Services\AgentSettlement\AgentSettlementPeriodOpenService;
|
||||
use App\Support\AdminAgentSettlementScope;
|
||||
use App\Support\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class AgentSettlementPeriodStoreController extends Controller
|
||||
{
|
||||
public function __invoke(AdminSettlementPeriodStoreRequest $request): JsonResponse
|
||||
{
|
||||
public function __invoke(
|
||||
AdminSettlementPeriodStoreRequest $request,
|
||||
AgentSettlementPeriodOpenService $openService,
|
||||
): JsonResponse {
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
@@ -23,17 +25,10 @@ final class AgentSettlementPeriodStoreController extends Controller
|
||||
! AdminAgentSettlementScope::siteAccessible($admin, (int) $data['admin_site_id']),
|
||||
404,
|
||||
);
|
||||
AdminAgentSettlementScope::assertCanManageSitePeriods($admin);
|
||||
|
||||
$id = DB::table('settlement_periods')->insertGetId([
|
||||
'admin_site_id' => (int) $data['admin_site_id'],
|
||||
'period_start' => $data['period_start'],
|
||||
'period_end' => $data['period_end'],
|
||||
'status' => 'open',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$row = DB::table('settlement_periods')->where('id', $id)->first();
|
||||
$row = $openService->open($data);
|
||||
$id = (int) $row->id;
|
||||
|
||||
AuditLogger::recordForAdmin(
|
||||
$admin,
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\AgentSettlement;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\AgentSettlement\AgentSettlementReportQueryService;
|
||||
use App\Support\AgentSettlementPeriodWindow;
|
||||
use App\Support\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -79,10 +80,12 @@ final class AgentSettlementReportShowController extends Controller
|
||||
$row = DB::table('settlement_periods')->where('id', $periodId)->first();
|
||||
abort_if($row === null, 404);
|
||||
|
||||
return [
|
||||
'start' => (string) $row->period_start,
|
||||
'end' => (string) $row->period_end,
|
||||
];
|
||||
[$start, $end] = AgentSettlementPeriodWindow::boundStrings(
|
||||
(string) $row->period_start,
|
||||
(string) $row->period_end,
|
||||
);
|
||||
|
||||
return ['start' => $start, 'end' => $end];
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
|
||||
@@ -84,16 +84,24 @@ final class AdminPlayerTicketItemsIndexController extends Controller
|
||||
'currency_code' => $row->order?->currency_code,
|
||||
'play_code' => $row->play_code,
|
||||
'original_number' => $row->original_number,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_bet_amount' => $totalBet,
|
||||
'total_bet_amount_minor' => $totalBet,
|
||||
'total_bet_amount_formatted' => CurrencyFormatter::fromMinor($totalBet),
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'actual_deduct_amount' => $actualDeduct,
|
||||
'actual_deduct_amount_minor' => $actualDeduct,
|
||||
'actual_deduct_amount_formatted' => CurrencyFormatter::fromMinor($actualDeduct),
|
||||
'status' => $row->status,
|
||||
'fail_reason_code' => $row->fail_reason_code,
|
||||
'fail_reason_text' => $row->fail_reason_text,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'win_amount' => $winAmount,
|
||||
'win_amount_minor' => $winAmount,
|
||||
'win_amount_formatted' => CurrencyFormatter::fromMinor($winAmount),
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'jackpot_win_amount' => $jackpotWin,
|
||||
'jackpot_win_amount_minor' => $jackpotWin,
|
||||
'jackpot_win_amount_formatted' => CurrencyFormatter::fromMinor($jackpotWin),
|
||||
'placed_at' => $row->order?->created_at?->toIso8601String(),
|
||||
'updated_at' => $row->updated_at?->toIso8601String(),
|
||||
|
||||
@@ -66,11 +66,20 @@ final class AdminSettlementBatchIndexController extends Controller
|
||||
'paid_at' => $b->paid_at?->toIso8601String(),
|
||||
'total_ticket_count' => (int) $b->total_ticket_count,
|
||||
'total_win_count' => (int) $b->total_win_count,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_bet_amount' => $financial['total_bet_amount'],
|
||||
'total_bet_amount_minor' => $financial['total_bet_amount_minor'],
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_actual_deduct' => $financial['total_actual_deduct'],
|
||||
'total_actual_deduct_minor' => $financial['total_actual_deduct_minor'],
|
||||
// settlement_batches 表内派彩金额一直按 minor 存储。
|
||||
'total_payout_amount' => (int) $b->total_payout_amount,
|
||||
'total_payout_amount_minor' => (int) $b->total_payout_amount,
|
||||
'total_jackpot_payout_amount' => (int) $b->total_jackpot_payout_amount,
|
||||
'total_jackpot_payout_amount_minor' => (int) $b->total_jackpot_payout_amount,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'platform_profit' => $financial['platform_profit'],
|
||||
'platform_profit_minor' => $financial['platform_profit_minor'],
|
||||
'started_at' => $b->started_at?->toIso8601String(),
|
||||
'finished_at' => $b->finished_at?->toIso8601String(),
|
||||
'created_at' => $b->created_at?->toIso8601String(),
|
||||
|
||||
@@ -36,11 +36,20 @@ final class AdminSettlementBatchShowController extends Controller
|
||||
'paid_at' => $batch->paid_at?->toIso8601String(),
|
||||
'total_ticket_count' => (int) $batch->total_ticket_count,
|
||||
'total_win_count' => (int) $batch->total_win_count,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_bet_amount' => $financial['total_bet_amount'],
|
||||
'total_bet_amount_minor' => $financial['total_bet_amount_minor'],
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_actual_deduct' => $financial['total_actual_deduct'],
|
||||
'total_actual_deduct_minor' => $financial['total_actual_deduct_minor'],
|
||||
// settlement_batches 表内派彩金额一直按 minor 存储。
|
||||
'total_payout_amount' => (int) $batch->total_payout_amount,
|
||||
'total_payout_amount_minor' => (int) $batch->total_payout_amount,
|
||||
'total_jackpot_payout_amount' => (int) $batch->total_jackpot_payout_amount,
|
||||
'total_jackpot_payout_amount_minor' => (int) $batch->total_jackpot_payout_amount,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'platform_profit' => $financial['platform_profit'],
|
||||
'platform_profit_minor' => $financial['platform_profit_minor'],
|
||||
'started_at' => $batch->started_at?->toIso8601String(),
|
||||
'finished_at' => $batch->finished_at?->toIso8601String(),
|
||||
'created_at' => $batch->created_at?->toIso8601String(),
|
||||
|
||||
@@ -113,16 +113,24 @@ final class AdminTicketItemIndexController extends Controller
|
||||
'currency_code' => $row->order?->currency_code,
|
||||
'play_code' => $row->play_code,
|
||||
'original_number' => $row->original_number,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'total_bet_amount' => $totalBet,
|
||||
'total_bet_amount_minor' => $totalBet,
|
||||
'total_bet_amount_formatted' => CurrencyFormatter::fromMinor($totalBet),
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'actual_deduct_amount' => $actualDeduct,
|
||||
'actual_deduct_amount_minor' => $actualDeduct,
|
||||
'actual_deduct_amount_formatted' => CurrencyFormatter::fromMinor($actualDeduct),
|
||||
'status' => $row->status,
|
||||
'fail_reason_code' => $row->fail_reason_code,
|
||||
'fail_reason_text' => $row->fail_reason_text,
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'win_amount' => $winAmount,
|
||||
'win_amount_minor' => $winAmount,
|
||||
'win_amount_formatted' => CurrencyFormatter::fromMinor($winAmount),
|
||||
// 历史字段:保留兼容,实际单位为 minor。
|
||||
'jackpot_win_amount' => $jackpotWin,
|
||||
'jackpot_win_amount_minor' => $jackpotWin,
|
||||
'jackpot_win_amount_formatted' => CurrencyFormatter::fromMinor($jackpotWin),
|
||||
'placed_at' => $row->order?->created_at?->toIso8601String(),
|
||||
'updated_at' => $row->updated_at?->toIso8601String(),
|
||||
|
||||
Reference in New Issue
Block a user