feat: 拆分开奖与结算审核流程,新增手动结果录入、重开和派彩审批接口
This commit is contained in:
@@ -3,11 +3,9 @@
|
||||
namespace App\Services\Settlement;
|
||||
|
||||
use App\Models\Draw;
|
||||
use App\Models\Player;
|
||||
use App\Models\TicketItem;
|
||||
use App\Lottery\DrawStatus;
|
||||
use App\Models\JackpotPool;
|
||||
use App\Models\TicketOrder;
|
||||
use App\Models\DrawResultItem;
|
||||
use App\Models\DrawResultBatch;
|
||||
use App\Models\SettlementBatch;
|
||||
@@ -16,13 +14,12 @@ use App\Lottery\DrawResultBatchStatus;
|
||||
use App\Lottery\SettlementBatchStatus;
|
||||
use App\Models\TicketSettlementDetail;
|
||||
use App\Services\Ticket\RiskPoolService;
|
||||
use App\Services\Ticket\TicketWalletService;
|
||||
use App\Services\Jackpot\JackpotBurstAllocator;
|
||||
|
||||
/**
|
||||
* 阶段 6:对已发布开奖、处于 `settling` 的期号执行结算(匹配 → 回水派彩调整 → Jackpot 爆池分配 → 明细 → 风险池释放 → 入账)。
|
||||
* 阶段 6:对已发布开奖、处于 `settling` 的期号执行结算(匹配 → 回水派彩调整 → Jackpot 爆池分配 → 明细 → 风险池释放 → 待审核)。
|
||||
*
|
||||
* 幂等:同一 `draw` + 已发布 `result_batch` 若已有 `completed` 批次,则仅推进期号状态为 `settled`。
|
||||
* 派彩入账由审核通过后的独立 payout 动作执行,避免未确认结果直接入账。
|
||||
*/
|
||||
final class SettlementOrchestrator
|
||||
{
|
||||
@@ -30,7 +27,6 @@ final class SettlementOrchestrator
|
||||
private readonly SettlementMatcherRegistry $matchers,
|
||||
private readonly SettlementPayoutAdjuster $payoutAdjuster,
|
||||
private readonly JackpotBurstAllocator $jackpotBurst,
|
||||
private readonly TicketWalletService $wallet,
|
||||
private readonly RiskPoolService $riskPool,
|
||||
) {}
|
||||
|
||||
@@ -65,12 +61,16 @@ final class SettlementOrchestrator
|
||||
$existingDone = SettlementBatch::query()
|
||||
->where('draw_id', $locked->id)
|
||||
->where('result_batch_id', $publishedBatch->id)
|
||||
->where('status', SettlementBatchStatus::Completed->value)
|
||||
->whereIn('status', [
|
||||
SettlementBatchStatus::PendingReview->value,
|
||||
SettlementBatchStatus::Approved->value,
|
||||
SettlementBatchStatus::Paid->value,
|
||||
SettlementBatchStatus::Completed->value,
|
||||
])
|
||||
->first();
|
||||
|
||||
if ($existingDone !== null) {
|
||||
$locked->forceFill([
|
||||
'status' => DrawStatus::Settled->value,
|
||||
'settle_version' => (int) $existingDone->settle_version,
|
||||
])->save();
|
||||
|
||||
@@ -91,6 +91,7 @@ final class SettlementOrchestrator
|
||||
'result_batch_id' => $publishedBatch->id,
|
||||
'settle_version' => $nextSettleVersion,
|
||||
'status' => SettlementBatchStatus::Running->value,
|
||||
'review_status' => 'pending',
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
@@ -139,7 +140,6 @@ final class SettlementOrchestrator
|
||||
$totalJackpotPayout = (int) $burstOut['pool_payout'];
|
||||
}
|
||||
|
||||
$playerTotals = [];
|
||||
$ticketCount = 0;
|
||||
$winCount = 0;
|
||||
$totalPayout = 0;
|
||||
@@ -164,8 +164,8 @@ final class SettlementOrchestrator
|
||||
$item->forceFill([
|
||||
'win_amount' => $net,
|
||||
'jackpot_win_amount' => $jackpotShare,
|
||||
'settled_at' => now(),
|
||||
'status' => $finalCredit > 0 ? 'settled_win' : 'settled_lose',
|
||||
'settled_at' => null,
|
||||
'status' => $finalCredit > 0 ? 'pending_payout' : 'settled_lose',
|
||||
])->save();
|
||||
|
||||
if ($finalCredit > 0) {
|
||||
@@ -173,9 +173,6 @@ final class SettlementOrchestrator
|
||||
}
|
||||
$totalPayout += $finalCredit;
|
||||
|
||||
$pid = (int) $item->player_id;
|
||||
$playerTotals[$pid] = ($playerTotals[$pid] ?? 0) + $finalCredit;
|
||||
|
||||
$locks = [];
|
||||
foreach ($item->combinations as $c) {
|
||||
$locks[] = [
|
||||
@@ -186,16 +183,8 @@ final class SettlementOrchestrator
|
||||
$this->riskPool->release((int) $locked->id, $item, $locks);
|
||||
}
|
||||
|
||||
foreach ($playerTotals as $playerId => $amount) {
|
||||
if ($amount <= 0) {
|
||||
continue;
|
||||
}
|
||||
$player = Player::query()->whereKey($playerId)->firstOrFail();
|
||||
$this->wallet->creditSettlementPayout($player, $currency, $amount, (int) $batchRow->id);
|
||||
}
|
||||
|
||||
$batchRow->forceFill([
|
||||
'status' => SettlementBatchStatus::Completed->value,
|
||||
'status' => SettlementBatchStatus::PendingReview->value,
|
||||
'total_ticket_count' => $ticketCount,
|
||||
'total_win_count' => $winCount,
|
||||
'total_payout_amount' => $totalPayout,
|
||||
@@ -204,20 +193,10 @@ final class SettlementOrchestrator
|
||||
])->save();
|
||||
|
||||
$locked->forceFill([
|
||||
'status' => DrawStatus::Settled->value,
|
||||
'status' => DrawStatus::Settling->value,
|
||||
'settle_version' => $nextSettleVersion,
|
||||
])->save();
|
||||
|
||||
foreach ($ticketItems->pluck('order_id')->unique()->all() as $orderId) {
|
||||
$pending = TicketItem::query()
|
||||
->where('order_id', $orderId)
|
||||
->whereNotIn('status', ['settled_win', 'settled_lose'])
|
||||
->exists();
|
||||
if (! $pending) {
|
||||
TicketOrder::query()->whereKey($orderId)->update(['status' => 'settled']);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user