Files
lotteryLaravel/app/Http/Controllers/Api/V1/E2E/E2EDrawController.php
kang c83343e989
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
lotterLaravel E2E / e2e-api (push) Has been cancelled
fix(settlement): 操作记录分页、流水动作与坏账幂等加固
- 新增 settlement-operations 合并列表 API,收付/调账接口改为标准分页
- actionable_only 流水在内存过滤后正确分页
- 已结账单流水不再展示补差/冲正快捷动作
- 坏账核销支持 idempotency_key 并写入 result_bill_id
- 补充操作记录、流水与坏账幂等相关测试
2026-06-26 16:40:46 +08:00

133 lines
4.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Controllers\Api\V1\E2E;
use App\Lottery\ErrorCode;
use App\Lottery\DrawStatus;
use App\Support\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Artisan;
/**
* E2E 辅助:期号时间/状态快进。
*
* 真实生产链路下"等 12 分钟后封盘"是脆的——CI 跑 e2e 不可能等。
* 这里允许 e2e 直接 SQL 改 close_time / draw_time模拟
* - close-now: close_time 改到 1 秒前、status=closed
* - reopen: status=open、重置冷却期
* - inspect: 返回 draw 完整时间/状态快照
*
* 严格仅在 LOTTERY_E2E=true 时由 E2EServiceProvider 注册。
*/
final class E2EDrawController extends Controller
{
public function closeNow(Request $request, string $drawNo): JsonResponse
{
$draw = DB::table('draws')->where('draw_no', $drawNo)->first();
if (! $draw) {
return ApiResponse::error('draw not found', ErrorCode::NotFound->value, null, 404);
}
DB::table('draws')
->where('id', $draw->id)
->update([
'status' => DrawStatus::Closed->value,
'close_time' => now()->subSeconds(5),
'draw_time' => now()->subSeconds(3),
]);
return $this->inspectById((int) $draw->id);
}
/** 将冷静期结束时间改到过去,便于 tick 推进 cooldown → settling。 */
public function finishCooldown(Request $request, string $drawNo): JsonResponse
{
$draw = DB::table('draws')->where('draw_no', $drawNo)->first();
if (! $draw) {
return ApiResponse::error('draw not found', ErrorCode::NotFound->value, null, 404);
}
DB::table('draws')
->where('id', $draw->id)
->update([
'cooling_end_time' => now()->subSeconds(5),
'draw_time' => now()->subMinutes(2),
'close_time' => now()->subMinutes(3),
]);
return $this->inspectById((int) $draw->id);
}
public function reopen(Request $request, string $drawNo): JsonResponse
{
$draw = DB::table('draws')->where('draw_no', $drawNo)->first();
if (! $draw) {
return ApiResponse::error('draw not found', ErrorCode::NotFound->value, null, 404);
}
DB::table('draws')
->where('id', $draw->id)
->update([
'status' => DrawStatus::Open->value,
'start_time' => now()->subMinutes(5),
'close_time' => now()->addMinutes(20),
'draw_time' => now()->addMinutes(21),
'cooling_end_time' => null,
]);
return $this->inspectById((int) $draw->id);
}
public function inspect(Request $request, string $drawNo): JsonResponse
{
$draw = DB::table('draws')->where('draw_no', $drawNo)->first();
if (! $draw) {
return ApiResponse::error('draw not found', ErrorCode::NotFound->value, null, 404);
}
return $this->inspectById((int) $draw->id);
}
/** 同步跑一次 lottery:draw-tick不开调度。返回该 tick 推进的 draw_no 列表。 */
public function tick(Request $request): JsonResponse
{
try {
$exit = Artisan::call('lottery:draw-tick');
} catch (\Throwable $e) {
return ApiResponse::error(
'draw-tick failed: '.$e->getMessage(),
ErrorCode::InternalError->value,
['trace' => array_slice(explode("\n", $e->getTraceAsString()), 0, 5)],
500,
);
}
return ApiResponse::success([
'exit_code' => $exit,
'output' => Artisan::output(),
]);
}
private function inspectById(int $id): JsonResponse
{
$d = DB::table('draws')->where('id', $id)->first();
return ApiResponse::success([
'id' => (int) $d->id,
'draw_no' => $d->draw_no,
'status' => (string) $d->status,
'business_date' => $d->business_date,
'start_time' => $d->start_time,
'close_time' => $d->close_time,
'draw_time' => $d->draw_time,
'cooling_end_time' => $d->cooling_end_time,
'current_result_version' => (int) $d->current_result_version,
'settle_version' => (int) $d->settle_version,
'is_reopened' => (bool) $d->is_reopened,
]);
}
}