feat: 增强奖池与钱包服务的多币种支持能力
更新 JackpotManualBurstService:在解析头奖中奖者时支持币种代码处理。 重构 SettlementBatchWorkflowService:按币种聚合玩家派奖金额,确保各币种结算准确入账。 修改 SettlementOrchestrator:按币种分别处理奖池爆奖流程,提升派奖准确性。 优化 TicketWalletService:在派奖幂等键中加入币种信息,避免多币种场景下的重复处理问题。 新增测试用例,验证多币种派奖场景及待处理交易的正确处理逻辑。
This commit is contained in:
@@ -121,8 +121,7 @@ final class SettlementBatchWorkflowService
|
||||
}
|
||||
|
||||
$details = $locked->details()->with(['ticketItem.order'])->get();
|
||||
$playerTotals = [];
|
||||
$currencyByPlayer = [];
|
||||
$playerCurrencyTotals = [];
|
||||
|
||||
foreach ($details as $detail) {
|
||||
$item = $detail->ticketItem;
|
||||
@@ -132,20 +131,34 @@ final class SettlementBatchWorkflowService
|
||||
$finalCredit = (int) $detail->win_amount + (int) $detail->jackpot_allocation_amount;
|
||||
if ($finalCredit > 0) {
|
||||
$pid = (int) $item->player_id;
|
||||
$playerTotals[$pid] = ($playerTotals[$pid] ?? 0) + $finalCredit;
|
||||
$currencyByPlayer[$pid] = strtoupper((string) ($item->order?->currency_code ?? 'NPR'));
|
||||
$currency = strtoupper((string) ($item->order?->currency_code ?? 'NPR'));
|
||||
$aggregateKey = $pid.':'.$currency;
|
||||
if (! isset($playerCurrencyTotals[$aggregateKey])) {
|
||||
$playerCurrencyTotals[$aggregateKey] = [
|
||||
'player_id' => $pid,
|
||||
'currency_code' => $currency,
|
||||
'amount' => 0,
|
||||
];
|
||||
}
|
||||
$playerCurrencyTotals[$aggregateKey]['amount'] += $finalCredit;
|
||||
$item->forceFill(['status' => 'settled_win', 'settled_at' => now()])->save();
|
||||
} elseif ($item->status !== 'settled_lose') {
|
||||
$item->forceFill(['status' => 'settled_lose', 'settled_at' => now()])->save();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($playerTotals as $playerId => $amount) {
|
||||
foreach ($playerCurrencyTotals as $entry) {
|
||||
$amount = (int) $entry['amount'];
|
||||
if ($amount <= 0) {
|
||||
continue;
|
||||
}
|
||||
$player = Player::query()->whereKey($playerId)->firstOrFail();
|
||||
$this->wallet->creditSettlementPayout($player, $currencyByPlayer[$playerId] ?? 'NPR', $amount, (int) $locked->id);
|
||||
$player = Player::query()->whereKey((int) $entry['player_id'])->firstOrFail();
|
||||
$this->wallet->creditSettlementPayout(
|
||||
$player,
|
||||
(string) $entry['currency_code'],
|
||||
$amount,
|
||||
(int) $locked->id
|
||||
);
|
||||
}
|
||||
|
||||
$orderIds = TicketItem::query()
|
||||
@@ -184,23 +197,35 @@ final class SettlementBatchWorkflowService
|
||||
return;
|
||||
}
|
||||
|
||||
$orderId = TicketItem::query()->where('draw_id', $batch->draw_id)->value('order_id');
|
||||
$currencyCode = strtoupper((string) (TicketOrder::query()
|
||||
->whereKey($orderId)
|
||||
->value('currency_code') ?? 'NPR'));
|
||||
$details = $batch->details()->with(['ticketItem.order'])->get();
|
||||
$restoreByCurrency = [];
|
||||
foreach ($details as $detail) {
|
||||
$amount = (int) $detail->jackpot_allocation_amount;
|
||||
if ($amount <= 0) {
|
||||
continue;
|
||||
}
|
||||
$currency = strtoupper((string) ($detail->ticketItem?->order?->currency_code ?? 'NPR'));
|
||||
$restoreByCurrency[$currency] = ($restoreByCurrency[$currency] ?? 0) + $amount;
|
||||
}
|
||||
|
||||
$pool = JackpotPool::query()
|
||||
->where('currency_code', $currencyCode)
|
||||
->where('status', 1)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
if ($pool === null) {
|
||||
if ($restoreByCurrency === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pool->forceFill([
|
||||
'current_amount' => (int) $pool->current_amount + $restoreAmount,
|
||||
])->save();
|
||||
foreach ($restoreByCurrency as $currency => $amount) {
|
||||
$pool = JackpotPool::query()
|
||||
->where('currency_code', $currency)
|
||||
->where('status', 1)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
if ($pool === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pool->forceFill([
|
||||
'current_amount' => (int) $pool->current_amount + (int) $amount,
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user