feat: 增强票据与钱包服务的幂等性及错误处理能力

在 TicketItemShowController 与 TicketItemsIndexController 的响应中新增订单状态与失败原因字段。
更新 WalletLogsController:待对账列表支持按币种筛选。
在 TicketPlacementService 中引入幂等性校验,支持处理已退款订单的重复请求。
优化钱包相关操作的错误码与错误提示信息,提升问题定位与用户理解。
增强测试用例,验证票据下单流程中的新幂等性行为。
This commit is contained in:
2026-05-26 15:24:54 +08:00
parent c8c90e3e94
commit 36e50383ba
12 changed files with 154 additions and 23 deletions

View File

@@ -1131,12 +1131,12 @@ test('ticket place reverses wallet and releases risk when post deduction confirm
->and((int) RiskPool::query()->where('draw_id', $draw->id)->where('normalized_number', '1234')->value('locked_amount'))->toBe(0);
});
test('ticket place idempotency replays refunded order for same trace', function (): void {
test('ticket place idempotency rejects replay for refunded order with same trace', function (): void {
$player = ticketPlayerWithWallet();
$draw = ticketOpenDraw();
$trace = 'trace-refunded-replay';
$order = TicketOrder::query()->create([
TicketOrder::query()->create([
'order_no' => 'TO-REFUNDED-IDEM',
'player_id' => $player->id,
'draw_id' => $draw->id,
@@ -1152,14 +1152,12 @@ test('ticket place idempotency replays refunded order for same trace', function
$payload = array_merge(ticketPreviewPayload(), ['client_trace_id' => $trace]);
$replay = $this->withHeader('Authorization', 'Bearer dev:'.$player->id)
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
->postJson('/api/v1/ticket/place', $payload)
->assertOk()
->assertJsonPath('code', ErrorCode::Success->value)
->json('data');
->assertStatus(409)
->assertJsonPath('code', ErrorCode::BetIdempotentReplayRejected->value);
expect($replay['order_no'])->toBe($order->order_no)
->and(TicketOrder::query()->count())->toBe(1)
expect(TicketOrder::query()->count())->toBe(1)
->and(WalletTxn::query()->where('biz_type', 'bet_deduct')->count())->toBe(0);
});