fix(core): harden settlement and wallet integration
This commit is contained in:
@@ -5,10 +5,13 @@ namespace App\Services\Ticket;
|
||||
use App\Models\Draw;
|
||||
use App\Models\WalletTxn;
|
||||
use App\Models\TicketItem;
|
||||
use App\Models\BetProvider;
|
||||
use App\Models\TicketOrder;
|
||||
use App\Support\PlayerFundingMode;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\Player\PlayerCreditService;
|
||||
use App\Services\Draw\DrawHallSnapshotBuilder;
|
||||
use App\Services\Jackpot\JackpotContributionService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class TicketPendingConfirmReconcileService
|
||||
{
|
||||
@@ -17,6 +20,7 @@ final class TicketPendingConfirmReconcileService
|
||||
private readonly JackpotContributionService $jackpotContribution,
|
||||
private readonly DrawHallSnapshotBuilder $drawHallSnapshot,
|
||||
private readonly TicketWalletService $ticketWallet,
|
||||
private readonly PlayerCreditService $playerCredit,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -45,6 +49,13 @@ final class TicketPendingConfirmReconcileService
|
||||
return 'skipped';
|
||||
}
|
||||
|
||||
$player = $lockedOrder->player()->first();
|
||||
if ($player !== null && PlayerFundingMode::usesCredit($player)) {
|
||||
// 信用单的占额与 pending_confirm 在同一数据库事务提交;
|
||||
// 能读到该状态即代表占额成功,无需依赖仅钱包盘才有的 bet_deduct 流水。
|
||||
return $this->confirmOrder($lockedOrder);
|
||||
}
|
||||
|
||||
$hasPostedDeduct = WalletTxn::query()
|
||||
->where('biz_type', 'bet_deduct')
|
||||
->where('biz_no', $lockedOrder->order_no)
|
||||
@@ -114,6 +125,17 @@ final class TicketPendingConfirmReconcileService
|
||||
|
||||
private function refundStalePendingOrder(TicketOrder $lockedOrder, string $reasonCode): string
|
||||
{
|
||||
$player = $lockedOrder->player()->first();
|
||||
if ($player !== null && PlayerFundingMode::usesCredit($player)) {
|
||||
$this->playerCredit->reverseBetHold(
|
||||
$player,
|
||||
(int) $lockedOrder->total_actual_deduct,
|
||||
(int) $lockedOrder->id,
|
||||
);
|
||||
|
||||
return $this->refundPendingConfirmItems($lockedOrder, $reasonCode);
|
||||
}
|
||||
|
||||
$hasPostedDeduct = WalletTxn::query()
|
||||
->where('biz_type', 'bet_deduct')
|
||||
->where('biz_no', $lockedOrder->order_no)
|
||||
@@ -131,6 +153,15 @@ final class TicketPendingConfirmReconcileService
|
||||
|
||||
private function refundOrderWithoutDeduct(TicketOrder $lockedOrder): string
|
||||
{
|
||||
$player = $lockedOrder->player()->first();
|
||||
if ($player !== null && PlayerFundingMode::usesCredit($player)) {
|
||||
$this->playerCredit->reverseBetHold(
|
||||
$player,
|
||||
(int) $lockedOrder->total_actual_deduct,
|
||||
(int) $lockedOrder->id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->refundPendingConfirmItems($lockedOrder, 'pending_confirm_timeout');
|
||||
}
|
||||
|
||||
@@ -155,7 +186,7 @@ final class TicketPendingConfirmReconcileService
|
||||
if ($locks !== []) {
|
||||
$this->riskPool->release(
|
||||
(int) $lockedOrder->draw_id,
|
||||
(string) ($item->provider_code ?: \App\Models\BetProvider::DEFAULT_CODE),
|
||||
(string) ($item->provider_code ?: BetProvider::DEFAULT_CODE),
|
||||
$item,
|
||||
$locks,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user