feat: 切换 schema dump 基线并增强返点结算与管理校验
This commit is contained in:
23
README.md
23
README.md
@@ -11,6 +11,29 @@
|
||||
|
||||
侧栏与 `prd.*` 权限目录见 [`docs/admin-rbac.md`](docs/admin-rbac.md)。维护命令:`php artisan lottery:admin-auth-sync --audit`。
|
||||
|
||||
## 数据库基线
|
||||
|
||||
项目当前已经整理出一份**最终版基线结构**,并已将历史迁移链清理为 schema dump 模式:
|
||||
|
||||
- PostgreSQL 基线文件:[`database/schema/pgsql-schema.sql`](database/schema/pgsql-schema.sql)
|
||||
- 适用场景:**新环境初始化**
|
||||
- 后续 migration 目录:`database/migrations/`
|
||||
- 适用场景:**从当前基线之后继续新增结构变更**
|
||||
|
||||
推荐约定如下:
|
||||
|
||||
- 新环境初始化时,优先使用 Laravel schema dump,让框架先加载 `database/schema/pgsql-schema.sql`,再执行该时间点之后的新迁移。
|
||||
- 已上线或已有数据的环境,如果已经接受 schema dump 作为唯一基线,可不再保留历史 migration 文件。
|
||||
- 之后的数据库结构演进,从当前 schema dump 往后继续追加新的 migration。
|
||||
|
||||
当数据库结构发生一轮阶段性稳定变更后,可重新生成基线:
|
||||
|
||||
```bash
|
||||
php artisan schema:dump --database=pgsql
|
||||
```
|
||||
|
||||
如果只是日常开发中的普通字段变更,仍然按正常方式新增 migration 即可;等累积到一段时间后,再统一刷新一次 schema dump。
|
||||
|
||||
## About Laravel
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
|
||||
@@ -38,8 +38,8 @@ final class RiskCapItemsReplaceController extends Controller
|
||||
'items' => ['required', 'array', 'min:1'],
|
||||
'items.*.draw_id' => ['sometimes', 'nullable', 'integer', 'exists:draws,id'],
|
||||
'items.*.normalized_number' => ['required', 'string', 'size:4', 'regex:/^[0-9]{4}$/'],
|
||||
'items.*.cap_amount' => ['required', 'integer', 'min:0'],
|
||||
'items.*.cap_type' => ['required', 'string', 'max:16'],
|
||||
'items.*.cap_amount' => ['required', 'integer', 'min:1'],
|
||||
'items.*.cap_type' => ['required', 'string', 'in:default,per_number'],
|
||||
]);
|
||||
|
||||
$service->replaceItems($version, $data['items'], $admin);
|
||||
|
||||
@@ -50,6 +50,7 @@ final class AdminCurrencyDestroyController extends Controller
|
||||
$checks = [
|
||||
'玩家默认币种' => DB::table('players')->where('default_currency', $code),
|
||||
'玩家钱包' => DB::table('player_wallets')->where('currency_code', $code),
|
||||
'站点默认币种' => DB::table('admin_sites')->where('currency_code', $code),
|
||||
'转账单' => DB::table('transfer_orders')->where('currency_code', $code),
|
||||
'注单' => DB::table('ticket_orders')->where('currency_code', $code),
|
||||
'赔率配置' => DB::table('odds_items')->where('currency_code', $code),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Jackpot;
|
||||
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\Draw;
|
||||
use App\Models\JackpotPool;
|
||||
use App\Support\ApiResponse;
|
||||
use App\Support\ApiMessage;
|
||||
@@ -40,11 +41,21 @@ final class AdminJackpotPoolManualBurstController extends Controller
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'draw_id' => 'required|integer|exists:draws,id',
|
||||
'draw_id' => ['required'],
|
||||
]);
|
||||
|
||||
$drawId = $this->resolveDrawId(trim((string) $data['draw_id']));
|
||||
if ($drawId === null) {
|
||||
return ApiResponse::error(
|
||||
trans('validation.exists', ['attribute' => 'draw_id'], $request->lotteryLocale()),
|
||||
ErrorCode::ClientHttpError->value,
|
||||
['draw_id' => [trans('validation.exists', ['attribute' => 'draw_id'], $request->lotteryLocale())]],
|
||||
422,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = $this->service->execute($pool, (int) $data['draw_id']);
|
||||
$payload = $this->service->execute($pool, $drawId);
|
||||
} catch (\RuntimeException $e) {
|
||||
return ApiResponse::error(
|
||||
ApiMessage::get($request, 'jackpot_manual_burst_failed', [
|
||||
@@ -58,4 +69,22 @@ final class AdminJackpotPoolManualBurstController extends Controller
|
||||
|
||||
return ApiResponse::success($payload);
|
||||
}
|
||||
|
||||
private function resolveDrawId(string $drawRef): ?int
|
||||
{
|
||||
if ($drawRef === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ctype_digit($drawRef)) {
|
||||
$draw = Draw::query()->whereKey((int) $drawRef)->first();
|
||||
if ($draw !== null) {
|
||||
return (int) $draw->id;
|
||||
}
|
||||
}
|
||||
|
||||
$draw = Draw::query()->where('draw_no', $drawRef)->first();
|
||||
|
||||
return $draw !== null ? (int) $draw->id : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Support\AdminSiteScope;
|
||||
use App\Support\PlayerFundingMode;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/** DELETE /api/v1/admin/players/{player} */
|
||||
final class AdminPlayerDestroyController extends Controller
|
||||
@@ -25,13 +27,36 @@ final class AdminPlayerDestroyController extends Controller
|
||||
return $denied;
|
||||
}
|
||||
|
||||
$hasWallets = Player::query()
|
||||
->whereKey($player->getKey())
|
||||
->whereHas('wallets', static fn (Builder $q) => $q->where('balance', '!=', 0))
|
||||
if (PlayerFundingMode::usesCredit($player)) {
|
||||
$creditRow = DB::table('player_credit_accounts')
|
||||
->where('player_id', $player->getKey())
|
||||
->first();
|
||||
|
||||
$usedCredit = (int) ($creditRow->used_credit ?? 0);
|
||||
$frozenCredit = (int) ($creditRow->frozen_credit ?? 0);
|
||||
if ($usedCredit !== 0 || $frozenCredit !== 0) {
|
||||
return ApiMessage::errorResponse($request, 'admin.player_credit_in_use_blocks_delete', ErrorCode::ValidationFailed->value, null, 422);
|
||||
}
|
||||
} else {
|
||||
$hasWallets = Player::query()
|
||||
->whereKey($player->getKey())
|
||||
->whereHas('wallets', static fn (Builder $q) => $q->where('balance', '!=', 0))
|
||||
->exists();
|
||||
|
||||
if ($hasWallets) {
|
||||
return ApiMessage::errorResponse($request, 'admin.player_wallet_balance_blocks_delete', ErrorCode::ValidationFailed->value, null, 422);
|
||||
}
|
||||
}
|
||||
|
||||
$hasUnpaidSettlementBills = DB::table('settlement_bills')
|
||||
->where('owner_type', 'player')
|
||||
->where('owner_id', $player->getKey())
|
||||
->whereIn('status', ['confirmed', 'partial_paid', 'overdue'])
|
||||
->where('unpaid_amount', '>', 0)
|
||||
->exists();
|
||||
|
||||
if ($hasWallets) {
|
||||
return ApiMessage::errorResponse($request, 'admin.player_wallet_balance_blocks_delete', ErrorCode::ValidationFailed->value, null, 422);
|
||||
if ($hasUnpaidSettlementBills) {
|
||||
return ApiMessage::errorResponse($request, 'admin.player_unpaid_settlement_blocks_delete', ErrorCode::ValidationFailed->value, null, 422);
|
||||
}
|
||||
|
||||
$hasTickets = TicketOrder::query()
|
||||
@@ -42,6 +67,7 @@ final class AdminPlayerDestroyController extends Controller
|
||||
return ApiMessage::errorResponse($request, 'admin.player_has_tickets_blocks_delete', ErrorCode::ValidationFailed->value, null, 422);
|
||||
}
|
||||
|
||||
DB::table('player_credit_accounts')->where('player_id', $player->getKey())->delete();
|
||||
$player->wallets()->delete();
|
||||
$player->delete();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ final class AdminPlayerIndexController extends Controller
|
||||
|
||||
if ($keyword !== '') {
|
||||
$term = '%'.addcslashes($keyword, '%_\\').'%';
|
||||
$q->where(static function ($sub) use ($term): void {
|
||||
$q->where(static function ($sub) use ($term, $keyword): void {
|
||||
$sub->where('site_player_id', 'like', $term)
|
||||
->orWhere('username', 'like', $term)
|
||||
->orWhere('nickname', 'like', $term);
|
||||
|
||||
@@ -55,7 +55,7 @@ final class AdminPlayerStoreController extends Controller
|
||||
if ($isNative) {
|
||||
$sitePlayerId = $sitePlayerId !== ''
|
||||
? $sitePlayerId
|
||||
: 'native:'.Str::lower(Str::ulid());
|
||||
: $this->generateNativeSitePlayerId($siteCode);
|
||||
}
|
||||
|
||||
if ($sitePlayerId === '') {
|
||||
@@ -192,4 +192,20 @@ final class AdminPlayerStoreController extends Controller
|
||||
|
||||
return $rootId !== null ? (int) $rootId : null;
|
||||
}
|
||||
|
||||
private function generateNativeSitePlayerId(string $siteCode): string
|
||||
{
|
||||
$prefix = strtoupper(substr(preg_replace('/[^A-Za-z]/', '', $siteCode) ?: 'LP', 0, 2));
|
||||
$prefix = str_pad($prefix, 2, 'P');
|
||||
|
||||
do {
|
||||
$candidate = sprintf('%s%06d', $prefix, random_int(0, 999999));
|
||||
$exists = Player::query()
|
||||
->where('site_code', $siteCode)
|
||||
->where('site_player_id', $candidate)
|
||||
->exists();
|
||||
} while ($exists);
|
||||
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Reconcile;
|
||||
|
||||
use App\Models\TransferOrder;
|
||||
use App\Models\ReconcileJob;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ReconcileItem;
|
||||
@@ -20,6 +21,19 @@ final class ReconcileItemIndexController extends Controller
|
||||
->orderBy('id')
|
||||
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||
|
||||
$transferNos = collect($paginator->items())
|
||||
->map(fn (ReconcileItem $item) => $item->side_a_ref)
|
||||
->filter(fn ($value) => is_string($value) && $value !== '')
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$transferStatuses = $transferNos === []
|
||||
? []
|
||||
: TransferOrder::query()
|
||||
->whereIn('transfer_no', $transferNos)
|
||||
->pluck('status', 'transfer_no')
|
||||
->all();
|
||||
|
||||
return AdminApiList::jsonWith($paginator, fn (ReconcileItem $r) => [
|
||||
'id' => (int) $r->id,
|
||||
'side_a_ref' => $r->side_a_ref,
|
||||
@@ -27,6 +41,8 @@ final class ReconcileItemIndexController extends Controller
|
||||
'difference_amount' => (int) $r->difference_amount,
|
||||
'status' => $r->status,
|
||||
'resolved_at' => $r->resolved_at?->toIso8601String(),
|
||||
'is_resolved' => $r->resolved_at !== null || in_array($transferStatuses[$r->side_a_ref ?? ''] ?? null, ['success', 'reversed', 'manually_processed'], true),
|
||||
'current_transfer_status' => $transferStatuses[$r->side_a_ref ?? ''] ?? null,
|
||||
'created_at' => $r->created_at?->toIso8601String(),
|
||||
], [
|
||||
'job_id' => (int) $reconcile_job->id,
|
||||
|
||||
@@ -14,10 +14,16 @@ final class ReportJobIndexController extends Controller
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
$p = AdminApiList::readPaging($request);
|
||||
$reportType = trim((string) $request->query('report_type', ''));
|
||||
|
||||
$paginator = ReportJob::query()
|
||||
->orderByDesc('id')
|
||||
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||
$query = ReportJob::query()
|
||||
->orderByDesc('id');
|
||||
|
||||
if ($reportType !== '') {
|
||||
$query->where('report_type', $reportType);
|
||||
}
|
||||
|
||||
$paginator = $query->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||
|
||||
return AdminApiList::json($paginator, fn (ReportJob $j) => $this->row($j));
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ final class AdminTicketItemIndexController extends Controller
|
||||
->with([
|
||||
'draw:id,draw_no,business_date',
|
||||
'order:id,order_no,currency_code,created_at',
|
||||
'player:id,site_code,site_player_id,username,nickname,agent_node_id',
|
||||
'player:id,site_code,site_player_id,username,nickname,agent_node_id,funding_mode',
|
||||
'player.agentNode:id,code,name',
|
||||
])
|
||||
->orderByDesc('ticket_items.id');
|
||||
@@ -108,6 +108,8 @@ final class AdminTicketItemIndexController extends Controller
|
||||
'site_player_id' => $row->player?->site_player_id,
|
||||
'username' => $row->player?->username,
|
||||
'nickname' => $row->player?->nickname,
|
||||
'funding_mode' => $row->player?->funding_mode,
|
||||
'uses_credit' => $row->player?->funding_mode === 'credit',
|
||||
'order_no' => $row->order?->order_no,
|
||||
'draw_no' => $row->draw?->draw_no,
|
||||
'currency_code' => $row->order?->currency_code,
|
||||
|
||||
@@ -67,7 +67,7 @@ final class WalletTransactionListController extends Controller
|
||||
|
||||
$query = WalletTxn::query()
|
||||
->with([
|
||||
'player:id,site_code,site_player_id,username,nickname,agent_node_id',
|
||||
'player:id,site_code,site_player_id,username,nickname,agent_node_id,funding_mode,auth_source',
|
||||
'player.agentNode:id,code,name',
|
||||
])
|
||||
->orderByDesc('id');
|
||||
|
||||
@@ -18,7 +18,6 @@ final class SettingIndexController extends Controller
|
||||
/** @var list<string> */
|
||||
private const PUBLIC_GROUPS = [
|
||||
'frontend',
|
||||
'currency',
|
||||
];
|
||||
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
|
||||
@@ -18,8 +18,11 @@ final class TicketPreviewController extends Controller
|
||||
|
||||
public function __invoke(TicketPreviewRequest $request): JsonResponse
|
||||
{
|
||||
$player = $request->lotteryPlayer();
|
||||
abort_if($player === null, 500, 'lottery_player missing');
|
||||
|
||||
try {
|
||||
$data = $this->previewService->preview($request->validated());
|
||||
$data = $this->previewService->preview($player, $request->validated());
|
||||
} catch (TicketOperationException $e) {
|
||||
return ApiResponse::error(
|
||||
LotteryMessage::wallet($request, $e->lotteryCode),
|
||||
|
||||
@@ -43,10 +43,17 @@ final class AgentGameSettlementRecorder
|
||||
|
||||
$gameType = trim((string) ($item->play_code ?? '')) ?: '*';
|
||||
$snapshot = $this->snapshotBuilder->buildForPlayer($player, $gameType);
|
||||
$baseRebateRate = $this->baseRebateRateForTicketItem($item);
|
||||
$basicRebateRate = $this->normalizeRate($baseRebateRate + (float) $snapshot['rebate_rate']);
|
||||
$shareSnapshot = [
|
||||
...$snapshot,
|
||||
'base_rebate_rate' => $baseRebateRate,
|
||||
'basic_rebate_rate' => $basicRebateRate,
|
||||
];
|
||||
|
||||
$gameWinLoss = $this->platformWinLoss($item, $netWin, $terminalStatus);
|
||||
$validBet = (int) $item->total_bet_amount;
|
||||
$basicRebate = (int) round($validBet * $snapshot['rebate_rate']);
|
||||
$basicRebate = (int) round($validBet * $basicRebateRate);
|
||||
$extraRebate = (int) round($validBet * $snapshot['extra_rebate_rate']);
|
||||
|
||||
$extraByCode = [];
|
||||
@@ -66,15 +73,11 @@ final class AgentGameSettlementRecorder
|
||||
|
||||
$settledAt = now();
|
||||
|
||||
DB::transaction(function () use ($item, $player, $snapshot, $gameWinLoss, $basicRebate, $result, $settledAt, $validBet, $extraRebate, $gameType): void {
|
||||
DB::transaction(function () use ($item, $player, $snapshot, $shareSnapshot, $basicRebateRate, $gameWinLoss, $basicRebate, $result, $settledAt, $validBet, $extraRebate, $gameType): void {
|
||||
$item->forceFill([
|
||||
'agent_node_id' => $snapshot['agent_node_id'],
|
||||
'share_snapshot' => [
|
||||
'total_shares' => $snapshot['total_shares'],
|
||||
'actual_shares' => $snapshot['actual_shares'],
|
||||
'chain_codes' => $snapshot['chain_codes'],
|
||||
],
|
||||
'agent_rebate_rate_snapshot' => $snapshot['rebate_rate'],
|
||||
'share_snapshot' => $shareSnapshot,
|
||||
'agent_rebate_rate_snapshot' => $basicRebateRate,
|
||||
'agent_settled_at' => $settledAt,
|
||||
])->save();
|
||||
|
||||
@@ -83,7 +86,7 @@ final class AgentGameSettlementRecorder
|
||||
'player_id' => $player->id,
|
||||
'agent_node_id' => $snapshot['agent_node_id'],
|
||||
'agent_path' => json_encode($snapshot['agent_path']),
|
||||
'share_snapshot' => json_encode($snapshot),
|
||||
'share_snapshot' => json_encode($shareSnapshot),
|
||||
'game_win_loss' => (int) round($gameWinLoss),
|
||||
'basic_rebate' => $basicRebate,
|
||||
'shared_net_win_loss' => (int) round($result->sharedNetWinLoss),
|
||||
@@ -99,7 +102,7 @@ final class AgentGameSettlementRecorder
|
||||
'ticket_item_id' => $item->id,
|
||||
'game_type' => $gameType,
|
||||
'valid_bet_amount' => $validBet,
|
||||
'rebate_rate' => $snapshot['rebate_rate'],
|
||||
'rebate_rate' => $basicRebateRate,
|
||||
'rebate_amount' => $basicRebate,
|
||||
'rebate_type' => 'basic',
|
||||
'owner_agent_id' => $snapshot['agent_node_id'],
|
||||
@@ -138,6 +141,38 @@ final class AgentGameSettlementRecorder
|
||||
});
|
||||
}
|
||||
|
||||
private function baseRebateRateForTicketItem(TicketItem $item): float
|
||||
{
|
||||
$ruleSnapshot = is_array($item->rule_snapshot_json) ? $item->rule_snapshot_json : [];
|
||||
$baseFromRule = isset($ruleSnapshot['base_rebate_rate'])
|
||||
? (float) $ruleSnapshot['base_rebate_rate']
|
||||
: null;
|
||||
|
||||
if ($baseFromRule !== null && $baseFromRule > 0) {
|
||||
return $this->normalizeRate($baseFromRule);
|
||||
}
|
||||
|
||||
$oddsSnapshot = is_array($item->odds_snapshot_json) ? $item->odds_snapshot_json : [];
|
||||
foreach ($oddsSnapshot as $row) {
|
||||
if (! is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! array_key_exists('rebate_rate', $row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->normalizeRate((float) $row['rebate_rate']);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
private function normalizeRate(float $rate): float
|
||||
{
|
||||
return max(0.0, min(1.0, $rate));
|
||||
}
|
||||
|
||||
private function platformWinLoss(TicketItem $item, int $netWin, string $terminalStatus): float
|
||||
{
|
||||
if ($terminalStatus === 'settled_lose') {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Services\AgentSettlement;
|
||||
|
||||
use App\Models\Player;
|
||||
use App\Services\Player\PlayerCreditService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
@@ -10,6 +12,7 @@ final class AgentSettlementBadDebtService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AgentSettlementPeriodCompletionService $periodCompletion,
|
||||
private readonly PlayerCreditService $playerCreditService,
|
||||
) {}
|
||||
|
||||
public function writeOff(int $originalBillId, ?string $reason, int $adminUserId): int
|
||||
@@ -99,6 +102,13 @@ final class AgentSettlementBadDebtService
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
if ((string) $original->owner_type === 'player' && (int) $original->owner_id > 0 && (int) $original->net_amount > 0) {
|
||||
$player = Player::query()->find((int) $original->owner_id);
|
||||
if ($player !== null) {
|
||||
$this->playerCreditService->releaseFromSettlement($player, $unpaid, $originalBillId);
|
||||
}
|
||||
}
|
||||
|
||||
$this->periodCompletion->syncIfReady($periodId);
|
||||
|
||||
return $archiveBillId;
|
||||
|
||||
@@ -56,6 +56,20 @@ final class AgentSettlementBillGuard
|
||||
public function markConfirmed(int $billId): void
|
||||
{
|
||||
$this->assertPeriodMutable($billId);
|
||||
$bill = DB::table('settlement_bills')->where('id', $billId)->first();
|
||||
if ($bill === null) {
|
||||
throw new \InvalidArgumentException('bill_not_found');
|
||||
}
|
||||
|
||||
if ((string) $bill->status === 'confirmed') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((string) $bill->status !== 'pending_confirm') {
|
||||
throw ValidationException::withMessages([
|
||||
'bill' => ['not_confirmable'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::table('settlement_bills')->where('id', $billId)->update([
|
||||
'status' => 'confirmed',
|
||||
|
||||
@@ -18,7 +18,9 @@ final class SettlementCenterLedgerService
|
||||
'bet_hold',
|
||||
'bet_hold_release',
|
||||
'game_settlement_loss',
|
||||
'game_settlement_win',
|
||||
'settlement_confirm',
|
||||
'settlement_payout',
|
||||
];
|
||||
|
||||
private const ADJUSTMENT_BIZ_TYPES = [
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Services\AgentSettlement;
|
||||
use App\Models\Player;
|
||||
use App\Services\Player\PlayerCreditService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
final class SettlementPaymentService
|
||||
{
|
||||
@@ -25,66 +26,72 @@ final class SettlementPaymentService
|
||||
*/
|
||||
public function recordPayment(int $billId, int $amount, int $adminUserId, array $meta = []): void
|
||||
{
|
||||
$bill = DB::table('settlement_bills')->where('id', $billId)->first();
|
||||
if ($bill === null) {
|
||||
throw new \InvalidArgumentException('bill_not_found');
|
||||
}
|
||||
DB::transaction(function () use ($billId, $amount, $adminUserId, $meta): void {
|
||||
$bill = DB::table('settlement_bills')->where('id', $billId)->lockForUpdate()->first();
|
||||
if ($bill === null) {
|
||||
throw new \InvalidArgumentException('bill_not_found');
|
||||
}
|
||||
|
||||
$this->billGuard->assertPeriodMutable($billId);
|
||||
$this->billGuard->assertPayable($billId);
|
||||
$this->billGuard->assertPeriodMutable($billId);
|
||||
if (! in_array((string) $bill->status, ['confirmed', 'partial_paid', 'overdue'], true)) {
|
||||
throw ValidationException::withMessages([
|
||||
'bill' => ['not_payable'],
|
||||
]);
|
||||
}
|
||||
|
||||
$amount = min($amount, abs((int) $bill->unpaid_amount));
|
||||
if ($amount <= 0) {
|
||||
return;
|
||||
}
|
||||
$payAmount = min($amount, abs((int) $bill->unpaid_amount));
|
||||
if ($payAmount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[$payerType, $payerId, $payeeType, $payeeId] = $this->resolvePayerPayee($bill);
|
||||
[$payerType, $payerId, $payeeType, $payeeId] = $this->resolvePayerPayee($bill);
|
||||
|
||||
DB::table('payment_records')->insert([
|
||||
'settlement_bill_id' => $billId,
|
||||
'payer_type' => $payerType,
|
||||
'payer_id' => $payerId,
|
||||
'payee_type' => $payeeType,
|
||||
'payee_id' => $payeeId,
|
||||
'amount' => $amount,
|
||||
'method' => $meta['method'] ?? null,
|
||||
'proof' => $meta['proof'] ?? null,
|
||||
'remark' => $meta['remark'] ?? null,
|
||||
'status' => 'confirmed',
|
||||
'created_by' => $adminUserId,
|
||||
'confirmed_by' => $adminUserId,
|
||||
'confirmed_at' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
DB::table('payment_records')->insert([
|
||||
'settlement_bill_id' => $billId,
|
||||
'payer_type' => $payerType,
|
||||
'payer_id' => $payerId,
|
||||
'payee_type' => $payeeType,
|
||||
'payee_id' => $payeeId,
|
||||
'amount' => $payAmount,
|
||||
'method' => $meta['method'] ?? null,
|
||||
'proof' => $meta['proof'] ?? null,
|
||||
'remark' => $meta['remark'] ?? null,
|
||||
'status' => 'confirmed',
|
||||
'created_by' => $adminUserId,
|
||||
'confirmed_by' => $adminUserId,
|
||||
'confirmed_at' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$newPaid = (int) $bill->paid_amount + $amount;
|
||||
$newUnpaid = max(0, (int) $bill->unpaid_amount - $amount);
|
||||
$status = $newUnpaid === 0 ? 'settled' : 'partial_paid';
|
||||
$newPaid = (int) $bill->paid_amount + $payAmount;
|
||||
$newUnpaid = max(0, (int) $bill->unpaid_amount - $payAmount);
|
||||
$status = $newUnpaid === 0 ? 'settled' : 'partial_paid';
|
||||
|
||||
DB::table('settlement_bills')->where('id', $billId)->update([
|
||||
'paid_amount' => $newPaid,
|
||||
'unpaid_amount' => $newUnpaid,
|
||||
'status' => $status,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
DB::table('settlement_bills')->where('id', $billId)->update([
|
||||
'paid_amount' => $newPaid,
|
||||
'unpaid_amount' => $newUnpaid,
|
||||
'status' => $status,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
if ($bill->owner_type === 'player' && (int) $bill->owner_id > 0) {
|
||||
$player = Player::query()->find((int) $bill->owner_id);
|
||||
if ($player !== null) {
|
||||
if ((int) $bill->net_amount > 0) {
|
||||
$this->playerCreditService->releaseFromSettlement($player, $amount, $billId);
|
||||
} elseif ((int) $bill->net_amount < 0) {
|
||||
$this->playerCreditService->applySettlementPayout($player, $amount, $billId);
|
||||
}
|
||||
if ($bill->owner_type === 'player' && (int) $bill->owner_id > 0) {
|
||||
$player = Player::query()->find((int) $bill->owner_id);
|
||||
if ($player !== null) {
|
||||
if ((int) $bill->net_amount > 0) {
|
||||
$this->playerCreditService->releaseFromSettlement($player, $payAmount, $billId);
|
||||
} elseif ((int) $bill->net_amount < 0) {
|
||||
$this->playerCreditService->applySettlementPayout($player, $payAmount, $billId);
|
||||
}
|
||||
|
||||
if ($status === 'settled') {
|
||||
$this->periodCloseRebate->markRebatesSettledForBill($billId);
|
||||
if ($status === 'settled') {
|
||||
$this->periodCloseRebate->markRebatesSettledForBill($billId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->periodCompletion->syncIfReady((int) $bill->settlement_period_id);
|
||||
$this->periodCompletion->syncIfReady((int) $bill->settlement_period_id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ use App\Models\JackpotPool;
|
||||
use App\Models\JackpotContribution;
|
||||
|
||||
/**
|
||||
* 产品文档 §5.11.1:每笔有效注单按比例蓄水(在下注成功路径调用,非结算)。
|
||||
* 产品文档 §5.11.1:每笔满足门槛的有效注单按下注额比例蓄水(在下注成功路径调用,非结算)。
|
||||
*/
|
||||
final class JackpotContributionService
|
||||
{
|
||||
@@ -25,12 +25,14 @@ final class JackpotContributionService
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) $item->actual_deduct_amount < (int) $pool->min_bet_amount) {
|
||||
$betAmount = (int) $item->total_bet_amount;
|
||||
|
||||
if ($betAmount < (int) $pool->min_bet_amount) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rate = (float) $pool->contribution_rate;
|
||||
$contrib = (int) floor((int) $item->actual_deduct_amount * $rate);
|
||||
$contrib = (int) floor($betAmount * $rate);
|
||||
if ($contrib <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ use Illuminate\Support\Facades\Cache;
|
||||
*/
|
||||
final class LotterySettings
|
||||
{
|
||||
private const CURRENCY_DISPLAY_DECIMALS = 2;
|
||||
private const CURRENCY_DECIMAL_SEPARATOR = '.';
|
||||
private const CURRENCY_THOUSANDS_SEPARATOR = ',';
|
||||
|
||||
public static function defaultCurrency(): string
|
||||
{
|
||||
$fallback = (string) config('lottery.default_currency', 'NPR');
|
||||
@@ -70,25 +74,17 @@ final class LotterySettings
|
||||
|
||||
public static function currencyDisplayDecimals(): int
|
||||
{
|
||||
$fallback = (int) config('lottery.ui.format.currency.decimals', 2);
|
||||
|
||||
return max(0, min(12, (int) self::get('currency.display_decimals', $fallback)));
|
||||
return self::CURRENCY_DISPLAY_DECIMALS;
|
||||
}
|
||||
|
||||
public static function currencyDecimalSeparator(): string
|
||||
{
|
||||
return (string) self::get(
|
||||
'currency.decimal_separator',
|
||||
(string) config('lottery.ui.format.currency.decimal_separator', '.')
|
||||
);
|
||||
return self::CURRENCY_DECIMAL_SEPARATOR;
|
||||
}
|
||||
|
||||
public static function currencyThousandsSeparator(): string
|
||||
{
|
||||
return (string) self::get(
|
||||
'currency.thousands_separator',
|
||||
(string) config('lottery.ui.format.currency.thousands_separator', ',')
|
||||
);
|
||||
return self::CURRENCY_THOUSANDS_SEPARATOR;
|
||||
}
|
||||
|
||||
public static function cacheTtlSeconds(): int
|
||||
|
||||
58
app/Services/Ticket/InstantRebateResolver.php
Normal file
58
app/Services/Ticket/InstantRebateResolver.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Ticket;
|
||||
|
||||
use App\Models\AgentProfile;
|
||||
use App\Models\Player;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class InstantRebateResolver
|
||||
{
|
||||
/**
|
||||
* @return array{
|
||||
* base_rebate_rate: float,
|
||||
* player_addon_rebate_rate: float,
|
||||
* final_rebate_rate: float,
|
||||
* inherited_from_agent: bool
|
||||
* }
|
||||
*/
|
||||
public function resolveForPlayer(Player $player, string $playCode, float $baseRebateRate): array
|
||||
{
|
||||
$row = DB::table('player_rebate_profiles')
|
||||
->where('player_id', $player->id)
|
||||
->where('game_type', $playCode)
|
||||
->first();
|
||||
|
||||
if ($row === null) {
|
||||
$row = DB::table('player_rebate_profiles')
|
||||
->where('player_id', $player->id)
|
||||
->where('game_type', '*')
|
||||
->first();
|
||||
}
|
||||
|
||||
$addonRate = 0.0;
|
||||
$inheritedFromAgent = false;
|
||||
|
||||
if ($row !== null && ! (bool) $row->inherit_from_agent) {
|
||||
$addonRate = (float) $row->rebate_rate + (float) $row->extra_rebate_rate;
|
||||
} else {
|
||||
$inheritedFromAgent = true;
|
||||
$profile = $player->agent_node_id
|
||||
? AgentProfile::query()->where('agent_node_id', $player->agent_node_id)->first()
|
||||
: null;
|
||||
$addonRate = (float) ($profile?->default_player_rebate ?? 0);
|
||||
}
|
||||
|
||||
return [
|
||||
'base_rebate_rate' => $this->normalizeRate($baseRebateRate),
|
||||
'player_addon_rebate_rate' => $this->normalizeRate($addonRate),
|
||||
'final_rebate_rate' => $this->normalizeRate($baseRebateRate + $addonRate),
|
||||
'inherited_from_agent' => $inheritedFromAgent,
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeRate(float $rate): float
|
||||
{
|
||||
return max(0.0, min(1.0, $rate));
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ final class TicketPlacementService
|
||||
public function __construct(
|
||||
private readonly PlayCatalogResolver $catalogResolver,
|
||||
private readonly PlayRuleEngine $ruleEngine,
|
||||
private readonly InstantRebateResolver $instantRebateResolver,
|
||||
private readonly RiskPoolService $riskPoolService,
|
||||
private readonly TicketWalletService $ticketWalletService,
|
||||
private readonly JackpotContributionService $jackpotContribution,
|
||||
@@ -532,12 +533,29 @@ final class TicketPlacementService
|
||||
*/
|
||||
private function applyCreditLineInstantRebatePolicy(Player $player, array $evaluated): array
|
||||
{
|
||||
if (! PlayerFundingMode::usesCredit($player)) {
|
||||
$resolved = $this->instantRebateResolver->resolveForPlayer(
|
||||
$player,
|
||||
(string) $evaluated['play_code'],
|
||||
(float) $evaluated['rebate_rate_snapshot'],
|
||||
);
|
||||
|
||||
$evaluated['rule_snapshot_json']['base_rebate_rate'] = number_format($resolved['base_rebate_rate'], 4, '.', '');
|
||||
$evaluated['rule_snapshot_json']['player_addon_rebate_rate'] = number_format($resolved['player_addon_rebate_rate'], 4, '.', '');
|
||||
$evaluated['rule_snapshot_json']['rebate_inherited_from_agent'] = $resolved['inherited_from_agent'];
|
||||
|
||||
if (PlayerFundingMode::usesCredit($player)) {
|
||||
$evaluated['rebate_rate_snapshot'] = '0.0000';
|
||||
$evaluated['actual_deduct_amount'] = (int) $evaluated['total_bet_amount'];
|
||||
|
||||
return $evaluated;
|
||||
}
|
||||
|
||||
$evaluated['rebate_rate_snapshot'] = '0.0000';
|
||||
$evaluated['actual_deduct_amount'] = (int) $evaluated['total_bet_amount'];
|
||||
$finalRate = $resolved['final_rebate_rate'];
|
||||
$evaluated['rebate_rate_snapshot'] = number_format($finalRate, 4, '.', '');
|
||||
$evaluated['actual_deduct_amount'] = max(
|
||||
0,
|
||||
(int) floor((int) $evaluated['total_bet_amount'] * (1 - $finalRate)),
|
||||
);
|
||||
|
||||
return $evaluated;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
namespace App\Services\Ticket;
|
||||
|
||||
use App\Models\Draw;
|
||||
use App\Models\Player;
|
||||
use App\Lottery\ErrorCode;
|
||||
use App\Exceptions\TicketOperationException;
|
||||
use App\Services\Draw\DrawHallSnapshotBuilder;
|
||||
use App\Support\PlayerFundingMode;
|
||||
|
||||
final class TicketPreviewService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly PlayCatalogResolver $catalogResolver,
|
||||
private readonly PlayRuleEngine $ruleEngine,
|
||||
private readonly InstantRebateResolver $instantRebateResolver,
|
||||
private readonly RiskPoolService $riskPoolService,
|
||||
private readonly DrawHallSnapshotBuilder $drawHallSnapshot,
|
||||
) {}
|
||||
@@ -20,7 +23,7 @@ final class TicketPreviewService
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function preview(array $payload): array
|
||||
public function preview(Player $player, array $payload): array
|
||||
{
|
||||
$drawNo = trim((string) ($payload['draw_id'] ?? ''));
|
||||
$draw = $drawNo === ''
|
||||
@@ -62,6 +65,7 @@ final class TicketPreviewService
|
||||
$resolved['play_config'],
|
||||
$resolved['odds_items'],
|
||||
);
|
||||
$evaluated = $this->applyPlayerInstantRebate($player, $evaluated);
|
||||
|
||||
$locks = array_map(fn (array $combo): array => [
|
||||
'number_4d' => $combo['number_4d'],
|
||||
@@ -131,4 +135,37 @@ final class TicketPreviewService
|
||||
'warnings' => $warningRows,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $evaluated
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function applyPlayerInstantRebate(Player $player, array $evaluated): array
|
||||
{
|
||||
$resolved = $this->instantRebateResolver->resolveForPlayer(
|
||||
$player,
|
||||
(string) $evaluated['play_code'],
|
||||
(float) $evaluated['rebate_rate_snapshot'],
|
||||
);
|
||||
|
||||
$evaluated['rule_snapshot_json']['base_rebate_rate'] = number_format($resolved['base_rebate_rate'], 4, '.', '');
|
||||
$evaluated['rule_snapshot_json']['player_addon_rebate_rate'] = number_format($resolved['player_addon_rebate_rate'], 4, '.', '');
|
||||
$evaluated['rule_snapshot_json']['rebate_inherited_from_agent'] = $resolved['inherited_from_agent'];
|
||||
|
||||
if (PlayerFundingMode::usesCredit($player)) {
|
||||
$evaluated['rebate_rate_snapshot'] = '0.0000';
|
||||
$evaluated['actual_deduct_amount'] = (int) $evaluated['total_bet_amount'];
|
||||
|
||||
return $evaluated;
|
||||
}
|
||||
|
||||
$finalRate = $resolved['final_rebate_rate'];
|
||||
$evaluated['rebate_rate_snapshot'] = number_format($finalRate, 4, '.', '');
|
||||
$evaluated['actual_deduct_amount'] = max(
|
||||
0,
|
||||
(int) floor((int) $evaluated['total_bet_amount'] * (1 - $finalRate)),
|
||||
);
|
||||
|
||||
return $evaluated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ final class PlayerLedgerLogsService
|
||||
'bet_hold_release',
|
||||
'game_settlement_loss',
|
||||
'game_settlement_win',
|
||||
'settlement_confirm',
|
||||
'settlement_payout',
|
||||
])->limit(5000)->get()->all();
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Support;
|
||||
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\Player;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
@@ -106,23 +108,29 @@ final class AuditLogApiPresenter
|
||||
{
|
||||
$items = collect($paginator->items());
|
||||
$resourceNames = self::loadResourceNames($items);
|
||||
$operatorLabels = self::loadOperatorLabels($items);
|
||||
|
||||
return AdminApiList::payload(
|
||||
$paginator,
|
||||
fn (AuditLog $r) => self::row($r, $resourceNames),
|
||||
fn (AuditLog $r) => self::row($r, $resourceNames, $operatorLabels),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $resourceNames
|
||||
* @param array<string, string> $operatorLabels
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function row(AuditLog $r, array $resourceNames = []): array
|
||||
public static function row(AuditLog $r, array $resourceNames = [], array $operatorLabels = []): array
|
||||
{
|
||||
$operatorDisplay = self::operatorDisplay($r, $operatorLabels);
|
||||
|
||||
return [
|
||||
'id' => (int) $r->id,
|
||||
'operator_type' => $r->operator_type,
|
||||
'operator_id' => (int) $r->operator_id,
|
||||
'operator_label' => $operatorDisplay['label'],
|
||||
'operator_subtitle' => $operatorDisplay['subtitle'],
|
||||
'module_code' => $r->module_code,
|
||||
'action_code' => $r->action_code,
|
||||
'target_type' => $r->target_type,
|
||||
@@ -138,6 +146,57 @@ final class AuditLogApiPresenter
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, AuditLog> $items
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private static function loadOperatorLabels(Collection $items): array
|
||||
{
|
||||
$labels = [];
|
||||
|
||||
$adminIds = $items
|
||||
->filter(fn (AuditLog $row) => $row->operator_type === 'admin' && (int) $row->operator_id > 0)
|
||||
->pluck('operator_id')
|
||||
->map(fn (mixed $id): int => (int) $id)
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
if ($adminIds !== []) {
|
||||
$admins = AdminUser::query()
|
||||
->whereIn('id', $adminIds)
|
||||
->get(['id', 'username', 'name']);
|
||||
|
||||
foreach ($admins as $admin) {
|
||||
$labels['admin:'.$admin->id] = self::formatIdentityLabel(
|
||||
(string) ($admin->name ?? ''),
|
||||
(string) ($admin->username ?? ''),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$playerIds = $items
|
||||
->filter(fn (AuditLog $row) => $row->operator_type === 'player' && (int) $row->operator_id > 0)
|
||||
->pluck('operator_id')
|
||||
->map(fn (mixed $id): int => (int) $id)
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
if ($playerIds !== []) {
|
||||
$players = Player::query()
|
||||
->whereIn('id', $playerIds)
|
||||
->get(['id', 'username', 'nickname']);
|
||||
|
||||
foreach ($players as $player) {
|
||||
$labels['player:'.$player->id] = self::formatIdentityLabel(
|
||||
(string) ($player->nickname ?? ''),
|
||||
(string) ($player->username ?? ''),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, AuditLog> $items
|
||||
* @return array<string, string>
|
||||
@@ -171,6 +230,48 @@ final class AuditLogApiPresenter
|
||||
return self::MODULE_LABELS[$code] ?? $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $operatorLabels
|
||||
*/
|
||||
private static function operatorDisplay(AuditLog $r, array $operatorLabels): array
|
||||
{
|
||||
$type = (string) ($r->operator_type ?? '');
|
||||
$id = (int) ($r->operator_id ?? 0);
|
||||
|
||||
if ($type === 'system') {
|
||||
return ['label' => '系统', 'subtitle' => null];
|
||||
}
|
||||
|
||||
$key = $type.':'.$id;
|
||||
if (isset($operatorLabels[$key]) && $operatorLabels[$key] !== '') {
|
||||
return [
|
||||
'label' => $operatorLabels[$key],
|
||||
'subtitle' => $id > 0 ? sprintf('%s #%d', $type === 'admin' ? '管理员' : ($type === 'player' ? '玩家' : $type), $id) : null,
|
||||
];
|
||||
}
|
||||
|
||||
$fallbackLabel = match ($type) {
|
||||
'admin' => $id > 0 ? '管理员 #'.$id : '管理员',
|
||||
'player' => $id > 0 ? '玩家 #'.$id : '玩家',
|
||||
'system' => '系统',
|
||||
default => $id > 0 ? sprintf('%s #%d', $type !== '' ? $type : '未知', $id) : ($type !== '' ? $type : '未知'),
|
||||
};
|
||||
|
||||
return ['label' => $fallbackLabel, 'subtitle' => null];
|
||||
}
|
||||
|
||||
private static function formatIdentityLabel(string $primary, string $secondary): string
|
||||
{
|
||||
$primary = trim($primary);
|
||||
$secondary = trim($secondary);
|
||||
|
||||
if ($primary !== '') {
|
||||
return $primary;
|
||||
}
|
||||
|
||||
return $secondary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $resourceNames
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@ use App\Services\LotterySettings;
|
||||
/**
|
||||
* 将「最小货币单位」整数格式化为展示用字符串(不改变业务数字,仅格式化)。
|
||||
*
|
||||
* 拆分位数由 {@see config('lottery.ui.format.currency.decimals')} 决定,默认 2(即 ÷100)。
|
||||
* 展示格式固定为 2 位小数、`.` 小数点、`,` 千分位;不从后台设置或环境变量读取。
|
||||
*/
|
||||
final class CurrencyFormatter
|
||||
{
|
||||
|
||||
@@ -112,16 +112,4 @@ return [
|
||||
'cooldown_minutes' => max(0, (int) env('LOTTERY_DRAW_COOLDOWN_MINUTES', 15)),
|
||||
],
|
||||
|
||||
/*
|
||||
| ui.format:API 中 *_formatted 展示用(由 {@see \App\Support\CurrencyFormatter} 读取)
|
||||
*/
|
||||
'ui' => [
|
||||
'format' => [
|
||||
'currency' => [
|
||||
'decimals' => max(0, min(12, (int) env('LOTTERY_CURRENCY_DISPLAY_DECIMALS', 2))),
|
||||
'decimal_separator' => env('LOTTERY_CURRENCY_DECIMAL_SEP', '.'),
|
||||
'thousands_separator' => env('LOTTERY_CURRENCY_THOUSANDS_SEP', ','),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
1
database/migrations/.gitkeep
Normal file
1
database/migrations/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->bigInteger('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->bigInteger('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedSmallInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('currencies', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 16)->unique();
|
||||
$table->string('name', 64);
|
||||
$table->unsignedTinyInteger('decimal_places')->default(2);
|
||||
$table->boolean('is_enabled')->default(true);
|
||||
$table->boolean('is_bettable')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('currencies');
|
||||
}
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('players', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('site_code', 64);
|
||||
$table->string('site_player_id', 128);
|
||||
$table->string('username', 128)->nullable();
|
||||
$table->string('nickname', 128)->nullable();
|
||||
$table->string('default_currency', 16)->default('NPR');
|
||||
$table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=frozen,2=blocked');
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['site_code', 'site_player_id'], 'uk_players_site_player');
|
||||
$table->index('status', 'idx_players_status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('players');
|
||||
}
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name', 128);
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=disabled');
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_users');
|
||||
}
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_roles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('slug', 64)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('admin_permissions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('slug', 128)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('admin_role_permissions', function (Blueprint $table) {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
|
||||
$table->primary(['role_id', 'permission_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_user_roles', function (Blueprint $table) {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->primary(['admin_user_id', 'role_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_user_roles');
|
||||
Schema::dropIfExists('admin_role_permissions');
|
||||
Schema::dropIfExists('admin_permissions');
|
||||
Schema::dropIfExists('admin_roles');
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('player_wallets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->string('wallet_type', 32)->default('lottery');
|
||||
$table->string('currency_code', 16);
|
||||
$table->bigInteger('balance')->default(0);
|
||||
$table->bigInteger('frozen_balance')->default(0);
|
||||
$table->unsignedTinyInteger('status')->default(0)->comment('0=active,1=frozen');
|
||||
$table->unsignedBigInteger('version')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['player_id', 'wallet_type', 'currency_code'], 'uk_player_wallets_player_type_currency');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('player_wallets');
|
||||
}
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('wallet_txns', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('txn_no', 64)->unique();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('wallet_id')->constrained('player_wallets')->cascadeOnDelete();
|
||||
$table->string('biz_type', 32);
|
||||
$table->string('biz_no', 64)->nullable();
|
||||
$table->unsignedTinyInteger('direction')->comment('1=in,2=out');
|
||||
$table->bigInteger('amount');
|
||||
$table->bigInteger('balance_before');
|
||||
$table->bigInteger('balance_after');
|
||||
$table->string('status', 32);
|
||||
$table->string('external_ref_no', 64)->nullable();
|
||||
$table->string('idempotent_key', 64)->nullable();
|
||||
$table->string('remark', 255)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['player_id', 'created_at'], 'idx_wallet_txns_player_time');
|
||||
$table->index(['biz_type', 'biz_no'], 'idx_wallet_txns_biz');
|
||||
$table->unique(['idempotent_key', 'biz_type'], 'uk_wallet_txns_idempotent_biz');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('wallet_txns');
|
||||
}
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('transfer_orders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('transfer_no', 64)->unique();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->string('direction', 16);
|
||||
$table->string('currency_code', 16);
|
||||
$table->bigInteger('amount');
|
||||
$table->string('idempotent_key', 64)->unique();
|
||||
$table->string('status', 32);
|
||||
$table->json('external_request_payload')->nullable();
|
||||
$table->json('external_response_payload')->nullable();
|
||||
$table->string('external_ref_no', 64)->nullable();
|
||||
$table->string('fail_reason', 255)->nullable();
|
||||
$table->timestamp('finished_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['player_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('transfer_orders');
|
||||
}
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('draws', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('draw_no', 32)->unique();
|
||||
$table->date('business_date');
|
||||
$table->unsignedInteger('sequence_no');
|
||||
$table->string('status', 32);
|
||||
$table->timestamp('start_time')->nullable();
|
||||
$table->timestamp('close_time')->nullable();
|
||||
$table->timestamp('draw_time')->nullable();
|
||||
$table->timestamp('cooling_end_time')->nullable();
|
||||
$table->string('result_source', 16)->nullable()->comment('rng|manual');
|
||||
$table->unsignedInteger('current_result_version')->default(0);
|
||||
$table->unsignedInteger('settle_version')->default(0);
|
||||
$table->boolean('is_reopened')->default(false);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['status', 'draw_time'], 'idx_draws_status_draw_time');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('draws');
|
||||
}
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('draw_result_batches', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->unsignedInteger('result_version');
|
||||
$table->string('source_type', 16)->comment('rng|manual');
|
||||
$table->string('rng_seed_hash', 128)->nullable();
|
||||
$table->text('raw_seed_encrypted')->nullable();
|
||||
$table->string('status', 32);
|
||||
$table->foreignId('created_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->foreignId('confirmed_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['draw_id', 'result_version'], 'uk_draw_result_batches_draw_version');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('draw_result_batches');
|
||||
}
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('draw_result_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->foreignId('result_batch_id')->constrained('draw_result_batches')->cascadeOnDelete();
|
||||
$table->string('prize_type', 32);
|
||||
$table->unsignedInteger('prize_index')->default(0);
|
||||
$table->char('number_4d', 4);
|
||||
$table->char('suffix_3d', 3)->nullable();
|
||||
$table->char('suffix_2d', 2)->nullable();
|
||||
$table->unsignedTinyInteger('head_digit')->nullable();
|
||||
$table->unsignedTinyInteger('tail_digit')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['draw_id', 'prize_type', 'prize_index'], 'idx_draw_result_items_draw_prize');
|
||||
$table->index(['draw_id', 'number_4d'], 'idx_draw_result_items_draw_number');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('draw_result_items');
|
||||
}
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 默认 User 登录未使用:业务玩家为 players,后台为 admin_users。
|
||||
* sessions 表仍保留(SESSION_DRIVER=database),其 user_id 可为空,不依赖 users。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('play_types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('play_code', 32)->unique();
|
||||
$table->string('category', 16);
|
||||
$table->unsignedTinyInteger('dimension')->nullable()->comment('2/3/4');
|
||||
$table->string('bet_mode', 32)->nullable();
|
||||
$table->string('display_name_zh', 64)->nullable();
|
||||
$table->string('display_name_en', 64)->nullable();
|
||||
$table->string('display_name_ne', 64)->nullable();
|
||||
$table->boolean('is_enabled')->default(true);
|
||||
$table->integer('sort_order')->default(0);
|
||||
$table->boolean('supports_multi_number')->default(false);
|
||||
$table->json('reserved_rule_json')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('play_types');
|
||||
}
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('play_config_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('version_no');
|
||||
$table->string('status', 16);
|
||||
$table->timestamp('effective_at')->nullable();
|
||||
$table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->string('reason', 255)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('play_config_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('version_id')->constrained('play_config_versions')->cascadeOnDelete();
|
||||
$table->string('play_code', 32);
|
||||
$table->boolean('is_enabled')->default(true);
|
||||
$table->bigInteger('min_bet_amount')->default(0);
|
||||
$table->bigInteger('max_bet_amount')->default(0);
|
||||
$table->integer('display_order')->default(0);
|
||||
$table->text('rule_text_zh')->nullable();
|
||||
$table->text('rule_text_en')->nullable();
|
||||
$table->text('rule_text_ne')->nullable();
|
||||
$table->json('extra_config_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['version_id', 'play_code'], 'uk_play_config_items_version_play');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('play_config_items');
|
||||
Schema::dropIfExists('play_config_versions');
|
||||
}
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('odds_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('version_no');
|
||||
$table->string('status', 16);
|
||||
$table->timestamp('effective_at')->nullable();
|
||||
$table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->string('reason', 255)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('odds_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('version_id')->constrained('odds_versions')->cascadeOnDelete();
|
||||
$table->string('play_code', 32);
|
||||
$table->string('prize_scope', 32);
|
||||
$table->bigInteger('odds_value')->default(0);
|
||||
$table->decimal('rebate_rate', 8, 4)->default(0);
|
||||
$table->decimal('commission_rate', 8, 4)->default(0);
|
||||
$table->string('currency_code', 16);
|
||||
$table->json('extra_config_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['version_id', 'play_code'], 'idx_odds_items_version_play');
|
||||
$table->unique(
|
||||
['version_id', 'play_code', 'prize_scope', 'currency_code'],
|
||||
'uk_odds_items_version_play_prize_currency'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('odds_items');
|
||||
Schema::dropIfExists('odds_versions');
|
||||
}
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('risk_cap_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('version_no');
|
||||
$table->string('status', 16);
|
||||
$table->timestamp('effective_at')->nullable();
|
||||
$table->foreignId('updated_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->string('reason', 255)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('risk_cap_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('version_id')->constrained('risk_cap_versions')->cascadeOnDelete();
|
||||
$table->foreignId('draw_id')->nullable()->constrained('draws')->nullOnDelete();
|
||||
$table->char('normalized_number', 4);
|
||||
$table->bigInteger('cap_amount');
|
||||
$table->string('cap_type', 16);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['version_id', 'draw_id', 'normalized_number'], 'idx_risk_cap_items_lookup');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('risk_cap_items');
|
||||
Schema::dropIfExists('risk_cap_versions');
|
||||
}
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('ticket_orders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('order_no', 64)->unique();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->string('currency_code', 16);
|
||||
$table->bigInteger('total_bet_amount')->default(0);
|
||||
$table->bigInteger('total_rebate_amount')->default(0);
|
||||
$table->bigInteger('total_actual_deduct')->default(0);
|
||||
$table->bigInteger('total_estimated_payout')->default(0);
|
||||
$table->string('status', 32);
|
||||
$table->string('submit_source', 16)->default('h5');
|
||||
$table->string('client_trace_id', 64)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['player_id', 'draw_id'], 'idx_ticket_orders_player_draw');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('ticket_orders');
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('ticket_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('ticket_no', 64)->unique();
|
||||
$table->foreignId('order_id')->constrained('ticket_orders')->cascadeOnDelete();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->string('original_number', 32)->nullable();
|
||||
$table->char('normalized_number', 4);
|
||||
$table->string('play_code', 32);
|
||||
$table->unsignedTinyInteger('dimension')->nullable()->comment('2/3/4');
|
||||
$table->unsignedTinyInteger('digit_slot')->nullable()->comment('千百十个位,领域字典');
|
||||
$table->string('bet_mode', 32)->nullable();
|
||||
$table->bigInteger('unit_bet_amount')->default(0);
|
||||
$table->bigInteger('total_bet_amount')->default(0);
|
||||
$table->decimal('rebate_rate_snapshot', 8, 4)->default(0);
|
||||
$table->decimal('commission_rate_snapshot', 8, 4)->default(0);
|
||||
$table->bigInteger('actual_deduct_amount')->default(0);
|
||||
$table->json('odds_snapshot_json')->nullable();
|
||||
$table->json('rule_snapshot_json')->nullable();
|
||||
$table->unsignedInteger('combination_count')->default(1);
|
||||
$table->bigInteger('estimated_max_payout')->default(0);
|
||||
$table->bigInteger('risk_locked_amount')->default(0);
|
||||
$table->string('status', 32);
|
||||
$table->string('fail_reason_code', 32)->nullable();
|
||||
$table->string('fail_reason_text', 255)->nullable();
|
||||
$table->bigInteger('win_amount')->default(0);
|
||||
$table->bigInteger('jackpot_win_amount')->default(0);
|
||||
$table->timestamp('settled_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['player_id', 'draw_id'], 'idx_ticket_items_player_draw');
|
||||
$table->index(['draw_id', 'status'], 'idx_ticket_items_draw_status');
|
||||
$table->index(['draw_id', 'normalized_number'], 'idx_ticket_items_draw_number');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('ticket_items');
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('ticket_combinations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('ticket_item_id')->constrained('ticket_items')->cascadeOnDelete();
|
||||
$table->unsignedInteger('combination_no')->default(0);
|
||||
$table->char('number_4d', 4);
|
||||
$table->bigInteger('bet_amount')->default(0);
|
||||
$table->bigInteger('estimated_payout')->default(0);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index('ticket_item_id', 'idx_ticket_combinations_item');
|
||||
$table->index('number_4d', 'idx_ticket_combinations_number');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('ticket_combinations');
|
||||
}
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('risk_pools', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->char('normalized_number', 4);
|
||||
$table->bigInteger('total_cap_amount')->default(0);
|
||||
$table->bigInteger('locked_amount')->default(0);
|
||||
$table->bigInteger('remaining_amount')->default(0);
|
||||
$table->unsignedTinyInteger('sold_out_status')->default(0);
|
||||
$table->unsignedBigInteger('version')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['draw_id', 'normalized_number'], 'uk_risk_pools_draw_number');
|
||||
$table->index(['draw_id', 'sold_out_status'], 'idx_risk_pools_draw_soldout');
|
||||
});
|
||||
|
||||
Schema::create('risk_pool_lock_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->char('normalized_number', 4);
|
||||
$table->foreignId('ticket_item_id')->nullable()->constrained('ticket_items')->nullOnDelete();
|
||||
$table->string('action_type', 16);
|
||||
$table->bigInteger('amount')->default(0);
|
||||
$table->string('source_reason', 32)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['draw_id', 'normalized_number'], 'idx_risk_lock_logs_draw_number');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('risk_pool_lock_logs');
|
||||
Schema::dropIfExists('risk_pools');
|
||||
}
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('settlement_batches', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->foreignId('result_batch_id')->constrained('draw_result_batches')->cascadeOnDelete();
|
||||
$table->unsignedInteger('settle_version')->default(1);
|
||||
$table->string('status', 32);
|
||||
$table->unsignedInteger('total_ticket_count')->default(0);
|
||||
$table->unsignedInteger('total_win_count')->default(0);
|
||||
$table->bigInteger('total_payout_amount')->default(0);
|
||||
$table->bigInteger('total_jackpot_payout_amount')->default(0);
|
||||
$table->string('review_status', 32)->default('pending');
|
||||
$table->foreignId('reviewed_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->timestamp('reviewed_at')->nullable();
|
||||
$table->string('review_remark', 255)->nullable();
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
$table->timestamp('started_at')->nullable();
|
||||
$table->timestamp('finished_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['draw_id', 'settle_version'], 'idx_settlement_batches_draw_version');
|
||||
});
|
||||
|
||||
Schema::create('ticket_settlement_details', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('settlement_batch_id')->constrained('settlement_batches')->cascadeOnDelete();
|
||||
$table->foreignId('ticket_item_id')->constrained('ticket_items')->cascadeOnDelete();
|
||||
$table->string('matched_prize_tier', 32)->nullable();
|
||||
$table->bigInteger('win_amount')->default(0);
|
||||
$table->bigInteger('jackpot_allocation_amount')->default(0);
|
||||
$table->json('match_detail_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['settlement_batch_id', 'ticket_item_id'], 'uk_ticket_settlement_batch_ticket');
|
||||
});
|
||||
|
||||
Schema::create('jackpot_pools', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('currency_code', 16)->unique();
|
||||
$table->bigInteger('current_amount')->default(0);
|
||||
$table->decimal('contribution_rate', 8, 4)->default(0);
|
||||
$table->bigInteger('trigger_threshold')->default(0);
|
||||
$table->decimal('payout_rate', 8, 4)->default(0);
|
||||
$table->unsignedInteger('force_trigger_draw_gap')->default(0);
|
||||
$table->bigInteger('min_bet_amount')->default(0);
|
||||
$table->unsignedTinyInteger('status')->default(0)->comment('0=off,1=on');
|
||||
$table->foreignId('last_trigger_draw_id')->nullable()->constrained('draws')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('jackpot_contributions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('jackpot_pool_id')->constrained('jackpot_pools')->cascadeOnDelete();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('ticket_item_id')->nullable()->constrained('ticket_items')->nullOnDelete();
|
||||
$table->bigInteger('contribution_amount')->default(0);
|
||||
$table->string('currency_code', 16);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['draw_id', 'player_id'], 'idx_jackpot_contrib_draw_player');
|
||||
});
|
||||
|
||||
Schema::create('jackpot_payout_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_id')->constrained('draws')->cascadeOnDelete();
|
||||
$table->foreignId('jackpot_pool_id')->constrained('jackpot_pools')->cascadeOnDelete();
|
||||
$table->string('trigger_type', 32);
|
||||
$table->bigInteger('total_payout_amount')->default(0);
|
||||
$table->unsignedInteger('winner_count')->default(0);
|
||||
$table->json('trigger_snapshot_json')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jackpot_payout_logs');
|
||||
Schema::dropIfExists('jackpot_contributions');
|
||||
Schema::dropIfExists('jackpot_pools');
|
||||
Schema::dropIfExists('ticket_settlement_details');
|
||||
Schema::dropIfExists('settlement_batches');
|
||||
}
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('report_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('job_no', 64)->unique();
|
||||
$table->foreignId('admin_user_id')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->string('report_type', 64);
|
||||
$table->string('export_format', 16)->default('csv');
|
||||
$table->json('filter_json')->nullable();
|
||||
$table->string('status', 32);
|
||||
$table->string('output_path', 512)->nullable();
|
||||
$table->text('error_message')->nullable();
|
||||
$table->timestamp('finished_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('audit_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('operator_type', 16);
|
||||
$table->unsignedBigInteger('operator_id')->default(0);
|
||||
$table->string('module_code', 32)->nullable();
|
||||
$table->string('action_code', 32)->nullable();
|
||||
$table->string('target_type', 32)->nullable();
|
||||
$table->string('target_id', 64)->nullable();
|
||||
$table->json('before_json')->nullable();
|
||||
$table->json('after_json')->nullable();
|
||||
$table->string('ip', 64)->nullable();
|
||||
$table->string('user_agent', 255)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['operator_type', 'operator_id', 'created_at'], 'idx_audit_logs_operator_time');
|
||||
$table->index(['module_code', 'action_code'], 'idx_audit_logs_module_action');
|
||||
});
|
||||
|
||||
Schema::create('system_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('job_key', 128)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->string('schedule_cron', 64)->nullable();
|
||||
$table->boolean('is_enabled')->default(true);
|
||||
$table->timestamp('last_started_at')->nullable();
|
||||
$table->timestamp('last_finished_at')->nullable();
|
||||
$table->string('last_status', 32)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('reconcile_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('job_no', 64)->unique();
|
||||
$table->string('reconcile_type', 32);
|
||||
$table->string('status', 32);
|
||||
$table->timestamp('period_start')->nullable();
|
||||
$table->timestamp('period_end')->nullable();
|
||||
$table->json('summary_json')->nullable();
|
||||
$table->timestamp('finished_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('reconcile_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('reconcile_job_id')->constrained('reconcile_jobs')->cascadeOnDelete();
|
||||
$table->string('side_a_ref', 128)->nullable();
|
||||
$table->string('side_b_ref', 128)->nullable();
|
||||
$table->bigInteger('difference_amount')->default(0);
|
||||
$table->string('status', 32);
|
||||
$table->timestamp('resolved_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('reconcile_items');
|
||||
Schema::dropIfExists('reconcile_jobs');
|
||||
Schema::dropIfExists('system_jobs');
|
||||
Schema::dropIfExists('audit_logs');
|
||||
Schema::dropIfExists('report_jobs');
|
||||
}
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 【任务 3 · 配置中心】键值运行时配置。
|
||||
*
|
||||
* 与 `config/*.php` / `.env` 分工:
|
||||
* - 密钥、站点 URL 等仍以 env 为准,不进库或不在此表明文扩写密钥;
|
||||
* - 可随时由运营调整的开关、限额类配置放本表,读时走 LotterySettings 带缓存。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('lottery_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('setting_key', 160)->unique();
|
||||
$table->json('value_json');
|
||||
$table->string('group_name', 64)->default('general')->comment('控制台分组展示用');
|
||||
$table->string('description_zh')->nullable()->comment('运维说明');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('group_name', 'idx_lottery_settings_group');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('lottery_settings');
|
||||
}
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->text('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 将历史上重复时间戳的 migration 文件名同步到 migrations 表,避免重命名后被视为未执行。
|
||||
*
|
||||
* 新装库:UPDATE 命中 0 行,无影响。
|
||||
* 已有库:把旧文件名改为新文件名,与重命名后的 PHP 文件一致。
|
||||
*
|
||||
* 若从旧文件名升级且 `php artisan migrate` 报「列已存在」等重复执行错误,请先单独执行本文件再全量 migrate:
|
||||
* php artisan migrate --path=database/migrations/2026_05_09_119999_rename_duplicate_migration_filenames_in_table.php
|
||||
* php artisan migrate
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var array<string, string> */
|
||||
private const RENAMES = [
|
||||
'2026_05_09_120000_add_username_and_nullable_email_to_admin_users' => '2026_05_09_120001_add_username_and_nullable_email_to_admin_users',
|
||||
'2026_05_09_120000_migrate_draw_status_to_domain_dict' => '2026_05_09_120002_migrate_draw_status_to_domain_dict',
|
||||
'2026_05_25_120000_consolidate_play_display_name_columns' => '2026_05_25_120001_consolidate_play_display_name_columns',
|
||||
'2026_05_25_120000_expand_audit_logs_target_type' => '2026_05_25_120002_expand_audit_logs_target_type',
|
||||
'2026_05_25_120000_refine_admin_permission_granularity' => '2026_05_25_120003_refine_admin_permission_granularity',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
foreach (self::RENAMES as $from => $to) {
|
||||
DB::table('migrations')->where('migration', $from)->update(['migration' => $to]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (self::RENAMES as $from => $to) {
|
||||
DB::table('migrations')->where('migration', $to)->update(['migration' => $from]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->string('username', 64)->nullable()->after('id');
|
||||
});
|
||||
|
||||
$this->backfillUsernames();
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->string('username', 64)->nullable(false)->change();
|
||||
$table->unique('username');
|
||||
});
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->dropUnique(['email']);
|
||||
});
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->string('email')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->dropUnique(['username']);
|
||||
});
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->dropColumn('username');
|
||||
});
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->string('email')->nullable(false)->change();
|
||||
});
|
||||
|
||||
Schema::table('admin_users', function (Blueprint $table) {
|
||||
$table->unique('email');
|
||||
});
|
||||
}
|
||||
|
||||
private function backfillUsernames(): void
|
||||
{
|
||||
$reserved = [];
|
||||
|
||||
foreach (DB::table('admin_users')->orderBy('id')->cursor() as $row) {
|
||||
$email = (string) $row->email;
|
||||
$local = Str::lower(Str::before($email, '@'));
|
||||
$slug = preg_replace('/[^a-z0-9._-]/', '', $local);
|
||||
$base = Str::substr($slug !== '' ? $slug : 'admin'.(string) $row->id, 0, 50);
|
||||
if ($base === '') {
|
||||
$base = 'admin'.(string) $row->id;
|
||||
}
|
||||
|
||||
$candidate = $base;
|
||||
$n = 0;
|
||||
while (in_array($candidate, $reserved, true)
|
||||
|| DB::table('admin_users')->where('username', $candidate)->where('id', '!=', $row->id)->exists()) {
|
||||
$n++;
|
||||
$suffix = '_'.$n;
|
||||
$candidate = Str::substr($base, 0, 64 - strlen($suffix)).$suffix;
|
||||
}
|
||||
|
||||
$reserved[] = $candidate;
|
||||
|
||||
DB::table('admin_users')->where('id', $row->id)->update(['username' => $candidate]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 将旧版期号状态值迁移为《04-领域字典》约定。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::table('draws')->where('status', 'pending_review')->update(['status' => 'review']);
|
||||
DB::table('draws')->where('status', 'published')->update(['status' => 'cooldown']);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::table('draws')->where('status', 'review')->update(['status' => 'pending_review']);
|
||||
DB::table('draws')->where('status', 'cooldown')->update(['status' => 'published']);
|
||||
}
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('reconcile_jobs', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')
|
||||
->nullable()
|
||||
->constrained('admin_users')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('reconcile_jobs', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('admin_user_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_user_permissions', function (Blueprint $table) {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
|
||||
$table->primary(['admin_user_id', 'permission_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_user_permissions');
|
||||
}
|
||||
};
|
||||
@@ -1,728 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->createTables();
|
||||
$this->seedInitialData();
|
||||
$this->migrateLegacyAssignments();
|
||||
$this->dropLegacyTables();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->recreateLegacyTables();
|
||||
$this->migrateBackToLegacyTables();
|
||||
|
||||
Schema::dropIfExists('admin_user_site_roles');
|
||||
Schema::dropIfExists('admin_user_menu_actions');
|
||||
Schema::dropIfExists('admin_user_data_scopes');
|
||||
Schema::dropIfExists('admin_role_menu_actions');
|
||||
Schema::dropIfExists('admin_role_api_resources');
|
||||
Schema::dropIfExists('admin_role_menus');
|
||||
Schema::dropIfExists('admin_role_data_scopes');
|
||||
Schema::dropIfExists('admin_api_resource_bindings');
|
||||
Schema::dropIfExists('admin_api_resources');
|
||||
Schema::dropIfExists('admin_menu_actions');
|
||||
Schema::dropIfExists('admin_action_catalog');
|
||||
Schema::dropIfExists('admin_menus');
|
||||
Schema::dropIfExists('admin_data_scopes');
|
||||
Schema::dropIfExists('admin_sites');
|
||||
}
|
||||
|
||||
private function createTables(): void
|
||||
{
|
||||
Schema::create('admin_sites', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code', 64)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->string('currency_code', 16)->default('NPR');
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->boolean('is_default')->default(false);
|
||||
$table->json('extra_json')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::table('admin_roles', function (Blueprint $table): void {
|
||||
$table->string('code', 64)->nullable()->after('id');
|
||||
$table->text('description')->nullable()->after('name');
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled')->after('description');
|
||||
$table->boolean('is_system')->default(false)->after('status');
|
||||
$table->unsignedInteger('sort_order')->default(0)->after('is_system');
|
||||
});
|
||||
|
||||
DB::table('admin_roles')->update([
|
||||
'code' => DB::raw('slug'),
|
||||
'status' => 1,
|
||||
'is_system' => true,
|
||||
'sort_order' => 0,
|
||||
]);
|
||||
|
||||
Schema::table('admin_roles', function (Blueprint $table): void {
|
||||
$table->string('code', 64)->nullable(false)->change();
|
||||
$table->unique('code');
|
||||
});
|
||||
|
||||
Schema::create('admin_menus', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('parent_id')->nullable()->constrained('admin_menus')->nullOnDelete();
|
||||
$table->string('menu_type', 24)->comment('directory|menu|page');
|
||||
$table->string('code', 128)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->string('path', 255)->nullable();
|
||||
$table->string('route_name', 255)->nullable();
|
||||
$table->string('component', 255)->nullable();
|
||||
$table->string('icon', 128)->nullable();
|
||||
$table->string('active_menu_code', 128)->nullable();
|
||||
$table->unsignedInteger('sort_order')->default(0);
|
||||
$table->boolean('is_visible')->default(true);
|
||||
$table->boolean('is_cache')->default(false);
|
||||
$table->boolean('is_external')->default(false);
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->json('meta_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['parent_id', 'sort_order'], 'idx_admin_menus_parent_sort');
|
||||
});
|
||||
|
||||
Schema::create('admin_action_catalog', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code', 64)->unique();
|
||||
$table->string('name', 64);
|
||||
$table->unsignedInteger('sort_order')->default(0);
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('admin_menu_actions', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('menu_id')->constrained('admin_menus')->cascadeOnDelete();
|
||||
$table->foreignId('action_id')->constrained('admin_action_catalog')->cascadeOnDelete();
|
||||
$table->string('permission_code', 128)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['menu_id', 'action_id'], 'uk_admin_menu_actions_menu_action');
|
||||
$table->index(['menu_id', 'status'], 'idx_admin_menu_actions_menu_status');
|
||||
});
|
||||
|
||||
Schema::create('admin_api_resources', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code', 128)->unique();
|
||||
$table->string('module_code', 64);
|
||||
$table->string('name', 128);
|
||||
$table->string('http_method', 16);
|
||||
$table->string('uri_pattern', 255);
|
||||
$table->string('route_name', 255)->nullable();
|
||||
$table->string('auth_mode', 24)->default('permission_required')->comment('login_only|permission_required|internal_only');
|
||||
$table->boolean('is_audit_required')->default(false);
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->json('meta_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['module_code', 'status'], 'idx_admin_api_resources_module_status');
|
||||
});
|
||||
|
||||
Schema::create('admin_api_resource_bindings', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('api_resource_id')->constrained('admin_api_resources')->cascadeOnDelete();
|
||||
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['api_resource_id', 'menu_action_id'], 'uk_admin_api_bindings_api_action');
|
||||
});
|
||||
|
||||
Schema::create('admin_data_scopes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code', 64)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->string('scope_type', 32)->comment('all_sites|site_only|site_all_data|site_single_player|self_only');
|
||||
$table->string('module_code', 64)->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('admin_role_menus', function (Blueprint $table): void {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('menu_id')->constrained('admin_menus')->cascadeOnDelete();
|
||||
$table->primary(['role_id', 'menu_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_role_menu_actions', function (Blueprint $table): void {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
|
||||
$table->primary(['role_id', 'menu_action_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_role_api_resources', function (Blueprint $table): void {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('api_resource_id')->constrained('admin_api_resources')->cascadeOnDelete();
|
||||
$table->primary(['role_id', 'api_resource_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_role_data_scopes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
|
||||
$table->foreignId('data_scope_id')->constrained('admin_data_scopes')->cascadeOnDelete();
|
||||
$table->string('module_code', 64)->nullable();
|
||||
$table->json('constraint_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['role_id', 'site_id', 'data_scope_id', 'module_code'], 'uk_admin_role_data_scopes');
|
||||
});
|
||||
|
||||
Schema::create('admin_user_site_roles', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('site_id')->constrained('admin_sites')->cascadeOnDelete();
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->timestamp('granted_at')->nullable();
|
||||
$table->primary(['admin_user_id', 'site_id', 'role_id'], 'pk_admin_user_site_roles');
|
||||
});
|
||||
|
||||
Schema::create('admin_user_menu_actions', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
|
||||
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
|
||||
$table->timestamp('granted_at')->nullable();
|
||||
$table->primary(['admin_user_id', 'site_id', 'menu_action_id'], 'pk_admin_user_menu_actions');
|
||||
});
|
||||
|
||||
Schema::create('admin_user_data_scopes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('site_id')->nullable()->constrained('admin_sites')->nullOnDelete();
|
||||
$table->foreignId('data_scope_id')->constrained('admin_data_scopes')->cascadeOnDelete();
|
||||
$table->string('module_code', 64)->nullable();
|
||||
$table->json('constraint_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['admin_user_id', 'site_id', 'data_scope_id', 'module_code'], 'uk_admin_user_data_scopes');
|
||||
});
|
||||
}
|
||||
|
||||
private function seedInitialData(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
DB::table('admin_sites')->insert([
|
||||
'code' => 'default_site',
|
||||
'name' => '默认站点',
|
||||
'currency_code' => 'NPR',
|
||||
'status' => 1,
|
||||
'is_default' => true,
|
||||
'extra_json' => json_encode(['source' => 'migration'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
DB::table('admin_action_catalog')->insert([
|
||||
['code' => 'view', 'name' => '查看', 'sort_order' => 10, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'create', 'name' => '新增', 'sort_order' => 20, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'update', 'name' => '编辑', 'sort_order' => 30, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'delete', 'name' => '删除', 'sort_order' => 40, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'review', 'name' => '审核', 'sort_order' => 50, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'publish', 'name' => '发布', 'sort_order' => 60, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'export', 'name' => '导出', 'sort_order' => 70, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'manage', 'name' => '管理', 'sort_order' => 80, 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
]);
|
||||
|
||||
DB::table('admin_data_scopes')->insert([
|
||||
['code' => 'all_sites', 'name' => '全站点', 'scope_type' => 'all_sites', 'module_code' => null, 'description' => '可访问所有站点数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'site_only', 'name' => '指定站点', 'scope_type' => 'site_only', 'module_code' => null, 'description' => '仅限授权站点登录和访问', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'site_all_data', 'name' => '站点内全部数据', 'scope_type' => 'site_all_data', 'module_code' => null, 'description' => '可访问站点内全部业务数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'site_single_player', 'name' => '站点内单玩家', 'scope_type' => 'site_single_player', 'module_code' => 'player_service', 'description' => '仅限按指定玩家处理客诉与查单', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
['code' => 'self_only', 'name' => '仅本人相关', 'scope_type' => 'self_only', 'module_code' => 'audit', 'description' => '仅可查看与自身相关的数据', 'status' => 1, 'created_at' => $now, 'updated_at' => $now],
|
||||
]);
|
||||
|
||||
$this->seedMenuTree($now);
|
||||
$this->seedApiResources($now);
|
||||
}
|
||||
|
||||
private function seedMenuTree(Carbon $now): void
|
||||
{
|
||||
$menus = [
|
||||
['parent_code' => null, 'menu_type' => 'menu', 'code' => 'dashboard', 'name' => '仪表盘', 'path' => '/admin', 'route_name' => 'admin.dashboard', 'component' => 'dashboard/index', 'icon' => 'layout-dashboard', 'sort_order' => 10],
|
||||
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'draw', 'name' => '开奖管理', 'path' => '/admin/draws', 'route_name' => null, 'component' => null, 'icon' => 'dice-5', 'sort_order' => 20],
|
||||
['parent_code' => 'draw', 'menu_type' => 'page', 'code' => 'draw.results', 'name' => '开奖结果', 'path' => '/admin/draws', 'route_name' => 'admin.draws.index', 'component' => 'draw/results', 'icon' => null, 'sort_order' => 10],
|
||||
['parent_code' => 'draw', 'menu_type' => 'page', 'code' => 'draw.review', 'name' => '开奖审核', 'path' => '/admin/draws/review', 'route_name' => 'admin.draws.review', 'component' => 'draw/review', 'icon' => null, 'sort_order' => 20],
|
||||
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'config', 'name' => '运营配置', 'path' => '/admin/config', 'route_name' => null, 'component' => null, 'icon' => 'sliders-horizontal', 'sort_order' => 30],
|
||||
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.play', 'name' => '玩法开关', 'path' => '/admin/config/play-switches', 'route_name' => 'admin.config.play', 'component' => 'config/play', 'icon' => null, 'sort_order' => 10],
|
||||
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.odds', 'name' => '赔率配置', 'path' => '/admin/config/odds', 'route_name' => 'admin.config.odds', 'component' => 'config/odds', 'icon' => null, 'sort_order' => 20],
|
||||
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.risk_cap', 'name' => '封顶配置', 'path' => '/admin/config/play-limits', 'route_name' => 'admin.config.risk_cap', 'component' => 'config/risk-cap', 'icon' => null, 'sort_order' => 30],
|
||||
['parent_code' => 'config', 'menu_type' => 'page', 'code' => 'config.jackpot', 'name' => 'Jackpot 配置', 'path' => '/admin/jackpot/pools', 'route_name' => 'admin.jackpot.pools', 'component' => 'config/jackpot', 'icon' => null, 'sort_order' => 40],
|
||||
['parent_code' => null, 'menu_type' => 'page', 'code' => 'risk.monitor', 'name' => '风控监控', 'path' => '/admin/risk', 'route_name' => 'admin.risk.monitor', 'component' => 'risk/monitor', 'icon' => 'shield-alert', 'sort_order' => 40],
|
||||
['parent_code' => null, 'menu_type' => 'page', 'code' => 'settlement.batch', 'name' => '结算批次', 'path' => '/admin/settlement-batches', 'route_name' => 'admin.settlement.batches', 'component' => 'settlement/batches', 'icon' => 'receipt-text', 'sort_order' => 50],
|
||||
['parent_code' => null, 'menu_type' => 'directory', 'code' => 'service', 'name' => '客服财务', 'path' => '/admin/service-desk', 'route_name' => null, 'component' => null, 'icon' => 'hand-helping', 'sort_order' => 60],
|
||||
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.players', 'name' => '玩家查询', 'path' => '/admin/players', 'route_name' => 'admin.players.index', 'component' => 'service/players', 'icon' => null, 'sort_order' => 10],
|
||||
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.tickets', 'name' => '玩家注单', 'path' => '/admin/tickets', 'route_name' => 'admin.tickets.index', 'component' => 'service/tickets', 'icon' => null, 'sort_order' => 20],
|
||||
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.wallet', 'name' => '钱包流水', 'path' => '/admin/wallet/transactions', 'route_name' => 'admin.wallet.transactions', 'component' => 'service/wallet', 'icon' => null, 'sort_order' => 30],
|
||||
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.reconcile', 'name' => '对账管理', 'path' => '/admin/reconcile', 'route_name' => 'admin.reconcile.index', 'component' => 'service/reconcile', 'icon' => null, 'sort_order' => 40],
|
||||
['parent_code' => 'service', 'menu_type' => 'page', 'code' => 'service.audit', 'name' => '审计日志', 'path' => '/admin/audit-logs', 'route_name' => 'admin.audit.index', 'component' => 'service/audit', 'icon' => null, 'sort_order' => 60],
|
||||
['parent_code' => null, 'menu_type' => 'page', 'code' => 'system.admin_user', 'name' => '管理员权限', 'path' => '/admin/admin-users', 'route_name' => 'admin.system.admin-users', 'component' => 'system/admin-users', 'icon' => 'users-round', 'sort_order' => 70],
|
||||
['parent_code' => null, 'menu_type' => 'page', 'code' => 'system.admin_role', 'name' => '角色管理', 'path' => '/admin/admin-roles', 'route_name' => 'admin.system.admin-roles', 'component' => 'system/admin-roles', 'icon' => 'shield-check', 'sort_order' => 71],
|
||||
];
|
||||
|
||||
$menuIds = [];
|
||||
foreach ($menus as $menu) {
|
||||
$menuIds[$menu['code']] = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => $menu['parent_code'] === null ? null : $menuIds[$menu['parent_code']],
|
||||
'menu_type' => $menu['menu_type'],
|
||||
'code' => $menu['code'],
|
||||
'name' => $menu['name'],
|
||||
'path' => $menu['path'],
|
||||
'route_name' => $menu['route_name'],
|
||||
'component' => $menu['component'],
|
||||
'icon' => $menu['icon'],
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => $menu['sort_order'],
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$actionIds = DB::table('admin_action_catalog')->pluck('id', 'code');
|
||||
$menuActions = [
|
||||
['menu_code' => 'draw.results', 'action_code' => 'view', 'permission_code' => 'draw.results.view', 'name' => '开奖结果查看'],
|
||||
['menu_code' => 'draw.review', 'action_code' => 'review', 'permission_code' => 'draw.review.review', 'name' => '开奖审核'],
|
||||
['menu_code' => 'draw.review', 'action_code' => 'publish', 'permission_code' => 'draw.review.publish', 'name' => '开奖发布'],
|
||||
['menu_code' => 'config.play', 'action_code' => 'manage', 'permission_code' => 'config.play.manage', 'name' => '玩法开关管理'],
|
||||
['menu_code' => 'config.odds', 'action_code' => 'manage', 'permission_code' => 'config.odds.manage', 'name' => '赔率配置管理'],
|
||||
['menu_code' => 'config.risk_cap', 'action_code' => 'view', 'permission_code' => 'config.risk_cap.view', 'name' => '封顶配置查看'],
|
||||
['menu_code' => 'config.risk_cap', 'action_code' => 'manage', 'permission_code' => 'config.risk_cap.manage', 'name' => '封顶配置管理'],
|
||||
['menu_code' => 'config.jackpot', 'action_code' => 'view', 'permission_code' => 'config.jackpot.view', 'name' => 'Jackpot 查看'],
|
||||
['menu_code' => 'config.jackpot', 'action_code' => 'manage', 'permission_code' => 'config.jackpot.manage', 'name' => 'Jackpot 管理'],
|
||||
['menu_code' => 'risk.monitor', 'action_code' => 'view', 'permission_code' => 'risk.monitor.view', 'name' => '风控监控查看'],
|
||||
['menu_code' => 'settlement.batch', 'action_code' => 'view', 'permission_code' => 'settlement.batch.view', 'name' => '结算查看'],
|
||||
['menu_code' => 'settlement.batch', 'action_code' => 'review', 'permission_code' => 'settlement.batch.review', 'name' => '结算审核'],
|
||||
['menu_code' => 'settlement.batch', 'action_code' => 'manage', 'permission_code' => 'settlement.batch.manage', 'name' => '结算执行'],
|
||||
['menu_code' => 'service.players', 'action_code' => 'view', 'permission_code' => 'service.players.view', 'name' => '玩家查询查看'],
|
||||
['menu_code' => 'service.players', 'action_code' => 'manage', 'permission_code' => 'service.players.manage', 'name' => '玩家查询管理'],
|
||||
['menu_code' => 'service.players', 'action_code' => 'update', 'permission_code' => 'service.players.freeze', 'name' => '冻结解冻玩家'],
|
||||
['menu_code' => 'service.tickets', 'action_code' => 'view', 'permission_code' => 'service.tickets.view', 'name' => '玩家注单查看'],
|
||||
['menu_code' => 'service.wallet', 'action_code' => 'view', 'permission_code' => 'service.wallet.view', 'name' => '钱包流水查看'],
|
||||
['menu_code' => 'service.wallet', 'action_code' => 'manage', 'permission_code' => 'service.wallet.manage', 'name' => '钱包流水管理'],
|
||||
['menu_code' => 'service.reconcile', 'action_code' => 'view', 'permission_code' => 'service.reconcile.view', 'name' => '对账查看'],
|
||||
['menu_code' => 'service.reconcile', 'action_code' => 'manage', 'permission_code' => 'service.reconcile.manage', 'name' => '对账管理'],
|
||||
['menu_code' => 'service.audit', 'action_code' => 'view', 'permission_code' => 'service.audit.view', 'name' => '审计查看'],
|
||||
['menu_code' => 'system.admin_user', 'action_code' => 'manage', 'permission_code' => 'system.admin_user.manage', 'name' => '管理员权限管理'],
|
||||
['menu_code' => 'system.admin_role', 'action_code' => 'manage', 'permission_code' => 'system.admin_role.manage', 'name' => '角色权限管理'],
|
||||
];
|
||||
|
||||
foreach ($menuActions as $row) {
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => $menuIds[$row['menu_code']],
|
||||
'action_id' => $actionIds[$row['action_code']],
|
||||
'permission_code' => $row['permission_code'],
|
||||
'name' => $row['name'],
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function seedApiResources(Carbon $now): void
|
||||
{
|
||||
$resources = [
|
||||
['code' => 'admin.dashboard', 'module_code' => 'dashboard', 'name' => '后台仪表盘', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/dashboard', 'route_name' => 'api.v1.admin.dashboard', 'auth_mode' => 'login_only', 'is_audit_required' => false, 'permission_codes' => []],
|
||||
['code' => 'admin.draws.index', 'module_code' => 'draw', 'name' => '期开奖列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/draws', 'route_name' => 'api.v1.admin.draws.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['draw.results.view']],
|
||||
['code' => 'admin.draws.show', 'module_code' => 'draw', 'name' => '期开奖详情', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/draws/{draw}', 'route_name' => 'api.v1.admin.draws.show', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['draw.results.view']],
|
||||
['code' => 'admin.draws.publish', 'module_code' => 'draw', 'name' => '开奖发布', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/draws/{draw}/result-batches/{batch}/publish', 'route_name' => 'api.v1.admin.draws.result-batches.publish', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['draw.review.publish']],
|
||||
['code' => 'admin.draws.settlement.run', 'module_code' => 'settlement', 'name' => '执行结算', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/draws/{draw}/settlement/run', 'route_name' => 'api.v1.admin.draws.settlement.run', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['settlement.batch.manage', 'settlement.batch.review']],
|
||||
['code' => 'admin.wallet.transactions', 'module_code' => 'wallet', 'name' => '钱包流水查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/wallet/transactions', 'route_name' => 'api.v1.admin.wallet.transactions', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.wallet.view', 'service.wallet.manage']],
|
||||
['code' => 'admin.wallet.transfer-orders', 'module_code' => 'wallet', 'name' => '转账单查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/wallet/transfer-orders', 'route_name' => 'api.v1.admin.wallet.transfer-orders', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.wallet.view', 'service.wallet.manage']],
|
||||
['code' => 'admin.players.wallets', 'module_code' => 'player_service', 'name' => '玩家钱包查看', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/players/{player}/wallets', 'route_name' => 'api.v1.admin.players.wallets', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.players.manage', 'service.wallet.view']],
|
||||
['code' => 'admin.players.ticket-items', 'module_code' => 'player_service', 'name' => '玩家注单查看', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/players/{player}/ticket-items', 'route_name' => 'api.v1.admin.players.ticket-items.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.players.manage', 'service.tickets.view']],
|
||||
['code' => 'admin.reconcile.index', 'module_code' => 'reconcile', 'name' => '对账任务列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/reconcile-jobs', 'route_name' => 'api.v1.admin.reconcile-jobs.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.reconcile.view', 'service.reconcile.manage']],
|
||||
['code' => 'admin.reconcile.store', 'module_code' => 'reconcile', 'name' => '创建对账任务', 'http_method' => 'POST', 'uri_pattern' => '/api/v1/admin/reconcile-jobs', 'route_name' => 'api.v1.admin.reconcile-jobs.store', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['service.reconcile.manage']],
|
||||
['code' => 'admin.audit.index', 'module_code' => 'audit', 'name' => '审计日志查询', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/audit-logs', 'route_name' => 'api.v1.admin.audit-logs.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['service.audit.view']],
|
||||
['code' => 'admin.admin-users.index', 'module_code' => 'system', 'name' => '管理员列表', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/admin-users', 'route_name' => 'api.v1.admin.admin-users.index', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['system.admin_user.manage']],
|
||||
['code' => 'admin.admin-users.permission-catalog', 'module_code' => 'system', 'name' => '管理员权限目录', 'http_method' => 'GET', 'uri_pattern' => '/api/v1/admin/admin-user-permission-catalog', 'route_name' => 'api.v1.admin.admin-users.permission-catalog', 'auth_mode' => 'permission_required', 'is_audit_required' => false, 'permission_codes' => ['system.admin_user.manage']],
|
||||
['code' => 'admin.admin-users.permissions.sync', 'module_code' => 'system', 'name' => '管理员权限同步', 'http_method' => 'PUT', 'uri_pattern' => '/api/v1/admin/admin-users/{admin_user}/permissions', 'route_name' => 'api.v1.admin.admin-users.permissions.sync', 'auth_mode' => 'permission_required', 'is_audit_required' => true, 'permission_codes' => ['system.admin_user.manage']],
|
||||
];
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId([
|
||||
'code' => $resource['code'],
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
if (! isset($menuActionIds[$permissionCode])) {
|
||||
continue;
|
||||
}
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => $resourceId,
|
||||
'menu_action_id' => $menuActionIds[$permissionCode],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function migrateLegacyAssignments(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$defaultSiteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
|
||||
|
||||
$legacyRoles = DB::table('admin_roles')
|
||||
->select('id', 'code', 'slug', 'name')
|
||||
->get();
|
||||
|
||||
$legacyRoleAssignments = DB::table('admin_user_roles')->get();
|
||||
foreach ($legacyRoleAssignments as $row) {
|
||||
$legacyRoleId = (int) $row->role_id;
|
||||
DB::table('admin_user_site_roles')->insert([
|
||||
'admin_user_id' => (int) $row->admin_user_id,
|
||||
'site_id' => $defaultSiteId,
|
||||
'role_id' => $legacyRoleId,
|
||||
'granted_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$legacyPermissionById = DB::table('admin_permissions')->pluck('slug', 'id');
|
||||
$legacyRolePermissions = DB::table('admin_role_permissions')->get()->groupBy('role_id');
|
||||
$legacyUserPermissions = DB::table('admin_user_permissions')->get()->groupBy('admin_user_id');
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$apiResourceIdsByPermission = DB::table('admin_api_resource_bindings')
|
||||
->join('admin_menu_actions', 'admin_menu_actions.id', '=', 'admin_api_resource_bindings.menu_action_id')
|
||||
->select('admin_menu_actions.permission_code', 'admin_api_resource_bindings.api_resource_id')
|
||||
->get()
|
||||
->groupBy('permission_code')
|
||||
->map(static fn ($rows) => $rows->pluck('api_resource_id')->all());
|
||||
$menuIdsByPermission = DB::table('admin_menu_actions')
|
||||
->join('admin_menus', 'admin_menus.id', '=', 'admin_menu_actions.menu_id')
|
||||
->pluck('admin_menus.id', 'admin_menu_actions.permission_code');
|
||||
|
||||
$legacyToNewPermissionMap = [
|
||||
'prd.users.manage' => ['service.players.manage'],
|
||||
'prd.users.view_finance' => ['service.players.view', 'service.wallet.view'],
|
||||
'prd.users.view_cs' => ['service.players.view', 'service.tickets.view'],
|
||||
'prd.play_switch.manage' => ['config.play.manage'],
|
||||
'prd.odds.manage' => ['config.odds.manage'],
|
||||
'prd.risk_cap.manage' => ['config.risk_cap.manage'],
|
||||
'prd.risk_cap.view' => ['config.risk_cap.view'],
|
||||
'prd.rebate.manage' => ['config.odds.manage'],
|
||||
'prd.rebate.view' => ['config.odds.manage'],
|
||||
'prd.jackpot.manage' => ['config.jackpot.manage'],
|
||||
'prd.jackpot.view' => ['config.jackpot.view'],
|
||||
'prd.draw_result.manage' => ['draw.results.view', 'draw.review.review', 'draw.review.publish', 'risk.monitor.view'],
|
||||
'prd.draw_result.view' => ['draw.results.view', 'risk.monitor.view'],
|
||||
'prd.payout.manage' => ['settlement.batch.manage', 'settlement.batch.view'],
|
||||
'prd.payout.review' => ['settlement.batch.review', 'settlement.batch.view'],
|
||||
'prd.payout.view' => ['settlement.batch.view'],
|
||||
'prd.wallet_reconcile.manage' => ['service.wallet.manage', 'service.reconcile.manage'],
|
||||
'prd.wallet_reconcile.view' => ['service.wallet.view', 'service.reconcile.view'],
|
||||
'prd.wallet_reconcile.view_cs' => ['service.wallet.view', 'service.reconcile.view'],
|
||||
'prd.audit.all' => ['service.audit.view'],
|
||||
'prd.audit.self' => ['service.audit.view'],
|
||||
'prd.audit.finance' => ['service.audit.view'],
|
||||
'prd.admin_user.manage' => ['system.admin_user.manage'],
|
||||
'prd.player_freeze.manage' => ['service.players.freeze'],
|
||||
'prd.wallet_adjust.manage' => ['service.wallet.manage'],
|
||||
'prd.draw_reopen.manage' => ['draw.review.publish'],
|
||||
];
|
||||
|
||||
foreach ($legacyRoles as $role) {
|
||||
$roleId = (int) $role->id;
|
||||
|
||||
$grantedPermissions = [];
|
||||
foreach ($legacyRolePermissions->get((int) $role->id, collect()) as $pivot) {
|
||||
$permissionId = (int) $pivot->permission_id;
|
||||
$legacySlug = $legacyPermissionById[$permissionId] ?? null;
|
||||
if (! is_string($legacySlug)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($legacyToNewPermissionMap[$legacySlug] ?? [] as $permissionCode) {
|
||||
$grantedPermissions[$permissionCode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($grantedPermissions) as $permissionCode) {
|
||||
if (isset($menuIdsByPermission[$permissionCode])) {
|
||||
$this->grantMenuWithAncestors($roleId, (int) $menuIdsByPermission[$permissionCode]);
|
||||
}
|
||||
if (isset($menuActionIds[$permissionCode])) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => $roleId,
|
||||
'menu_action_id' => (int) $menuActionIds[$permissionCode],
|
||||
]);
|
||||
}
|
||||
foreach ($apiResourceIdsByPermission[$permissionCode] ?? [] as $apiResourceId) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => $roleId,
|
||||
'api_resource_id' => (int) $apiResourceId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$roleCode = (string) ($role->code ?: $role->slug);
|
||||
$this->assignRoleDataScopes($roleId, $roleCode, $defaultSiteId, $now);
|
||||
}
|
||||
|
||||
foreach ($legacyUserPermissions as $adminUserId => $pivots) {
|
||||
$grantedPermissions = [];
|
||||
foreach ($pivots as $pivot) {
|
||||
$permissionId = (int) $pivot->permission_id;
|
||||
$legacySlug = $legacyPermissionById[$permissionId] ?? null;
|
||||
if (! is_string($legacySlug)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($legacyToNewPermissionMap[$legacySlug] ?? [] as $permissionCode) {
|
||||
$grantedPermissions[$permissionCode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($grantedPermissions) as $permissionCode) {
|
||||
if (! isset($menuActionIds[$permissionCode])) {
|
||||
continue;
|
||||
}
|
||||
DB::table('admin_user_menu_actions')->updateOrInsert([
|
||||
'admin_user_id' => (int) $adminUserId,
|
||||
'site_id' => $defaultSiteId,
|
||||
'menu_action_id' => (int) $menuActionIds[$permissionCode],
|
||||
], [
|
||||
'granted_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function assignRoleDataScopes(int $roleId, string $roleCode, int $siteId, Carbon $now): void
|
||||
{
|
||||
$dataScopeIds = DB::table('admin_data_scopes')->pluck('id', 'code');
|
||||
|
||||
$rows = match ($roleCode) {
|
||||
'super_admin' => [
|
||||
['scope_code' => 'all_sites', 'module_code' => null],
|
||||
['scope_code' => 'site_all_data', 'module_code' => null],
|
||||
],
|
||||
'risk_operator' => [
|
||||
['scope_code' => 'site_only', 'module_code' => null],
|
||||
['scope_code' => 'site_all_data', 'module_code' => 'risk'],
|
||||
['scope_code' => 'self_only', 'module_code' => 'audit'],
|
||||
],
|
||||
'finance' => [
|
||||
['scope_code' => 'site_only', 'module_code' => null],
|
||||
['scope_code' => 'site_all_data', 'module_code' => 'wallet'],
|
||||
['scope_code' => 'site_all_data', 'module_code' => 'settlement'],
|
||||
['scope_code' => 'site_all_data', 'module_code' => 'report'],
|
||||
['scope_code' => 'site_all_data', 'module_code' => 'reconcile'],
|
||||
],
|
||||
'customer_service' => [
|
||||
['scope_code' => 'site_only', 'module_code' => null],
|
||||
['scope_code' => 'site_single_player', 'module_code' => 'player_service'],
|
||||
],
|
||||
default => [
|
||||
['scope_code' => 'site_only', 'module_code' => null],
|
||||
],
|
||||
};
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$scopeId = $dataScopeIds[$row['scope_code']] ?? null;
|
||||
if ($scopeId === null) {
|
||||
continue;
|
||||
}
|
||||
DB::table('admin_role_data_scopes')->insert([
|
||||
'role_id' => $roleId,
|
||||
'site_id' => $row['scope_code'] === 'all_sites' ? null : $siteId,
|
||||
'data_scope_id' => (int) $scopeId,
|
||||
'module_code' => $row['module_code'],
|
||||
'constraint_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function grantMenuWithAncestors(int $roleId, int $menuId): void
|
||||
{
|
||||
$currentMenuId = $menuId;
|
||||
|
||||
while ($currentMenuId > 0) {
|
||||
DB::table('admin_role_menus')->updateOrInsert([
|
||||
'role_id' => $roleId,
|
||||
'menu_id' => $currentMenuId,
|
||||
]);
|
||||
|
||||
$parentId = DB::table('admin_menus')->where('id', $currentMenuId)->value('parent_id');
|
||||
$currentMenuId = $parentId === null ? 0 : (int) $parentId;
|
||||
}
|
||||
}
|
||||
|
||||
private function dropLegacyTables(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_user_permissions');
|
||||
Schema::dropIfExists('admin_user_roles');
|
||||
Schema::dropIfExists('admin_role_permissions');
|
||||
Schema::dropIfExists('admin_permissions');
|
||||
}
|
||||
|
||||
private function recreateLegacyTables(): void
|
||||
{
|
||||
Schema::table('admin_roles', function (Blueprint $table): void {
|
||||
$table->dropUnique(['code']);
|
||||
$table->dropColumn(['code', 'description', 'status', 'is_system', 'sort_order']);
|
||||
});
|
||||
|
||||
Schema::create('admin_permissions', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('slug', 128)->unique();
|
||||
$table->string('name', 128);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('admin_role_permissions', function (Blueprint $table): void {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
|
||||
$table->primary(['role_id', 'permission_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_user_roles', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->primary(['admin_user_id', 'role_id']);
|
||||
});
|
||||
|
||||
Schema::create('admin_user_permissions', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('permission_id')->constrained('admin_permissions')->cascadeOnDelete();
|
||||
$table->primary(['admin_user_id', 'permission_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateBackToLegacyTables(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$legacyPermissions = [
|
||||
['slug' => 'prd.users.manage', 'name' => '用户管理·可管理'],
|
||||
['slug' => 'prd.users.view_finance', 'name' => '用户管理·财务查看'],
|
||||
['slug' => 'prd.users.view_cs', 'name' => '用户管理·客服单用户'],
|
||||
['slug' => 'prd.play_switch.manage', 'name' => '玩法开关·可管理'],
|
||||
['slug' => 'prd.odds.manage', 'name' => '赔率配置·可管理'],
|
||||
['slug' => 'prd.risk_cap.manage', 'name' => '封顶配置·可管理'],
|
||||
['slug' => 'prd.risk_cap.view', 'name' => '封顶配置·查看'],
|
||||
['slug' => 'prd.rebate.manage', 'name' => '佣金/回水·可管理'],
|
||||
['slug' => 'prd.rebate.view', 'name' => '佣金/回水·查看'],
|
||||
['slug' => 'prd.jackpot.manage', 'name' => 'Jackpot 配置·可管理'],
|
||||
['slug' => 'prd.jackpot.view', 'name' => 'Jackpot 配置·查看'],
|
||||
['slug' => 'prd.draw_result.manage', 'name' => '开奖结果录入·可管理'],
|
||||
['slug' => 'prd.draw_result.view', 'name' => '开奖结果·查看'],
|
||||
['slug' => 'prd.draw_reopen.manage', 'name' => '开奖结果重开·可管理'],
|
||||
['slug' => 'prd.payout.manage', 'name' => '派彩确认·可管理'],
|
||||
['slug' => 'prd.payout.review', 'name' => '派彩确认·可审核'],
|
||||
['slug' => 'prd.payout.view', 'name' => '派彩确认·查看'],
|
||||
['slug' => 'prd.wallet_reconcile.manage', 'name' => '钱包对账·可管理'],
|
||||
['slug' => 'prd.wallet_reconcile.view', 'name' => '钱包对账·查看'],
|
||||
['slug' => 'prd.wallet_reconcile.view_cs', 'name' => '钱包对账·客服单用户'],
|
||||
['slug' => 'prd.wallet_adjust.manage', 'name' => '补单/冲正·可管理'],
|
||||
['slug' => 'prd.audit.all', 'name' => '审计日志·全部'],
|
||||
['slug' => 'prd.audit.self', 'name' => '审计日志·自身相关'],
|
||||
['slug' => 'prd.audit.finance', 'name' => '审计日志·资金相关'],
|
||||
['slug' => 'prd.player_freeze.manage', 'name' => '冻结/解冻玩家·可管理'],
|
||||
['slug' => 'prd.admin_user.manage', 'name' => '后台用户权限管理·可管理'],
|
||||
];
|
||||
|
||||
foreach ($legacyPermissions as $permission) {
|
||||
DB::table('admin_permissions')->insert([
|
||||
'slug' => $permission['slug'],
|
||||
'name' => $permission['name'],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$permissionIds = DB::table('admin_permissions')->pluck('id', 'slug');
|
||||
$roleCodeMap = DB::table('admin_roles')->pluck('id', 'slug');
|
||||
|
||||
$rolePermissionMap = [
|
||||
'super_admin' => array_keys($permissionIds->all()),
|
||||
'risk_operator' => [
|
||||
'prd.play_switch.manage',
|
||||
'prd.odds.manage',
|
||||
'prd.risk_cap.manage',
|
||||
'prd.rebate.manage',
|
||||
'prd.jackpot.manage',
|
||||
'prd.draw_result.manage',
|
||||
'prd.payout.review',
|
||||
'prd.wallet_reconcile.view',
|
||||
'prd.audit.self',
|
||||
'prd.player_freeze.manage',
|
||||
],
|
||||
'finance' => [
|
||||
'prd.users.view_finance',
|
||||
'prd.risk_cap.view',
|
||||
'prd.rebate.view',
|
||||
'prd.jackpot.view',
|
||||
'prd.draw_result.view',
|
||||
'prd.payout.view',
|
||||
'prd.wallet_reconcile.manage',
|
||||
'prd.wallet_adjust.manage',
|
||||
'prd.audit.finance',
|
||||
],
|
||||
'customer_service' => [
|
||||
'prd.users.view_cs',
|
||||
'prd.draw_result.view',
|
||||
'prd.wallet_reconcile.view_cs',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($rolePermissionMap as $roleCode => $permissionSlugs) {
|
||||
$roleId = $roleCodeMap[$roleCode] ?? null;
|
||||
if ($roleId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($permissionSlugs as $slug) {
|
||||
$permissionId = $permissionIds[$slug] ?? null;
|
||||
if ($permissionId === null) {
|
||||
continue;
|
||||
}
|
||||
DB::table('admin_role_permissions')->insert([
|
||||
'role_id' => (int) $roleId,
|
||||
'permission_id' => (int) $permissionId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$userRoles = DB::table('admin_user_site_roles')
|
||||
->select('admin_user_id', 'role_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($userRoles as $row) {
|
||||
DB::table('admin_user_roles')->insert([
|
||||
'admin_user_id' => (int) $row->admin_user_id,
|
||||
'role_id' => (int) $row->role_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('play_config_items', function (Blueprint $table): void {
|
||||
$table->string('category', 16)->nullable()->after('play_code');
|
||||
$table->unsignedTinyInteger('dimension')->nullable()->after('category');
|
||||
$table->string('bet_mode', 32)->nullable()->after('dimension');
|
||||
$table->string('display_name_zh', 64)->nullable()->after('bet_mode');
|
||||
$table->string('display_name_en', 64)->nullable()->after('display_name_zh');
|
||||
$table->string('display_name_ne', 64)->nullable()->after('display_name_en');
|
||||
$table->boolean('supports_multi_number')->default(false)->after('display_name_ne');
|
||||
$table->json('reserved_rule_json')->nullable()->after('supports_multi_number');
|
||||
});
|
||||
|
||||
$playTypes = DB::table('play_types')
|
||||
->select([
|
||||
'play_code',
|
||||
'category',
|
||||
'dimension',
|
||||
'bet_mode',
|
||||
'display_name_zh',
|
||||
'display_name_en',
|
||||
'display_name_ne',
|
||||
'supports_multi_number',
|
||||
'reserved_rule_json',
|
||||
])
|
||||
->get()
|
||||
->keyBy('play_code');
|
||||
|
||||
DB::table('play_config_items')
|
||||
->select(['id', 'play_code'])
|
||||
->orderBy('id')
|
||||
->chunkById(200, function ($rows) use ($playTypes): void {
|
||||
foreach ($rows as $row) {
|
||||
$pt = $playTypes->get($row->play_code);
|
||||
if ($pt === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('play_config_items')
|
||||
->where('id', $row->id)
|
||||
->update([
|
||||
'category' => $pt->category,
|
||||
'dimension' => $pt->dimension,
|
||||
'bet_mode' => $pt->bet_mode,
|
||||
'display_name_zh' => $pt->display_name_zh,
|
||||
'display_name_en' => $pt->display_name_en,
|
||||
'display_name_ne' => $pt->display_name_ne,
|
||||
'supports_multi_number' => (bool) $pt->supports_multi_number,
|
||||
'reserved_rule_json' => $pt->reserved_rule_json,
|
||||
]);
|
||||
}
|
||||
}, 'id');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('play_config_items', function (Blueprint $table): void {
|
||||
$table->dropColumn([
|
||||
'category',
|
||||
'dimension',
|
||||
'bet_mode',
|
||||
'display_name_zh',
|
||||
'display_name_en',
|
||||
'display_name_ne',
|
||||
'supports_multi_number',
|
||||
'reserved_rule_json',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('jackpot_pools', function (Blueprint $table): void {
|
||||
$table->json('combo_trigger_play_codes')->nullable()->after('min_bet_amount');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('jackpot_pools', function (Blueprint $table): void {
|
||||
$table->dropColumn('combo_trigger_play_codes');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->unsignedInteger('play_config_version_no')->default(0)->after('client_trace_id');
|
||||
$table->unsignedInteger('odds_version_no')->default(0)->after('play_config_version_no');
|
||||
$table->unsignedInteger('risk_cap_version_no')->default(0)->after('odds_version_no');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->dropColumn([
|
||||
'play_config_version_no',
|
||||
'odds_version_no',
|
||||
'risk_cap_version_no',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::table('admin_role_api_resources')->delete();
|
||||
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->select('rma.role_id', 'arb.api_resource_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->insert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $row->api_resource_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 保持数据升级可逆风险最低:不在 down 中尝试删除资源,避免误删线上已使用授权关系。
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$currencyCodes = DB::table('currencies')
|
||||
->where('is_enabled', true)
|
||||
->where('is_bettable', true)
|
||||
->pluck('code')
|
||||
->filter(static fn ($code): bool => is_string($code) && trim($code) !== '')
|
||||
->map(static fn (string $code): string => strtoupper($code))
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($currencyCodes->isEmpty()) {
|
||||
$currencyCodes = collect([strtoupper((string) config('lottery.default_currency', 'NPR'))]);
|
||||
}
|
||||
|
||||
foreach ($currencyCodes as $currencyCode) {
|
||||
$exists = DB::table('jackpot_pools')->where('currency_code', $currencyCode)->exists();
|
||||
if ($exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('jackpot_pools')->insert([
|
||||
'currency_code' => $currencyCode,
|
||||
'current_amount' => 0,
|
||||
'contribution_rate' => '0.0200',
|
||||
'trigger_threshold' => 100_000_000,
|
||||
'payout_rate' => '0.5000',
|
||||
'force_trigger_draw_gap' => 100,
|
||||
'min_bet_amount' => 100,
|
||||
'status' => 0,
|
||||
'last_trigger_draw_id' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 保留奖池配置与水位,避免回滚误删运营数据。
|
||||
}
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Support\AdminPermissionBridge;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_role_legacy_permissions', function (Blueprint $table): void {
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->string('permission_slug', 128);
|
||||
$table->timestamps();
|
||||
|
||||
$table->primary(['role_id', 'permission_slug'], 'pk_admin_role_legacy_permissions');
|
||||
});
|
||||
|
||||
$now = now();
|
||||
$roleCodes = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_menu_actions as ma', 'ma.id', '=', 'rma.menu_action_id')
|
||||
->where('ma.status', 1)
|
||||
->select('rma.role_id', 'ma.permission_code')
|
||||
->get()
|
||||
->groupBy('role_id');
|
||||
|
||||
foreach ($roleCodes as $roleId => $rows) {
|
||||
$slugs = AdminPermissionBridge::legacySlugsGrantedByMenuActionCodes(
|
||||
$rows->pluck('permission_code')->all(),
|
||||
);
|
||||
foreach ($slugs as $slug) {
|
||||
DB::table('admin_role_legacy_permissions')->insert([
|
||||
'role_id' => (int) $roleId,
|
||||
'permission_slug' => $slug,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_role_legacy_permissions');
|
||||
}
|
||||
};
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use App\Support\AdminPermissionBridge;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$actionCatalogId = (int) DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
$adminUserMenuId = (int) DB::table('admin_menus')->where('code', 'system.admin_user')->value('id');
|
||||
|
||||
if ($adminUserMenuId > 0) {
|
||||
$adminUserMenu = DB::table('admin_menus')->where('id', $adminUserMenuId)->first();
|
||||
DB::table('admin_menus')->updateOrInsert(
|
||||
['code' => 'system.admin_role'],
|
||||
[
|
||||
'parent_id' => $adminUserMenu->parent_id,
|
||||
'menu_type' => 'page',
|
||||
'name' => '角色管理',
|
||||
'path' => '/admin/admin-roles',
|
||||
'route_name' => 'admin.system.admin-roles',
|
||||
'component' => 'system/admin-roles',
|
||||
'icon' => 'shield-check',
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => ((int) $adminUserMenu->sort_order) + 1,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$menuId = (int) DB::table('admin_menus')->where('code', 'system.admin_role')->value('id');
|
||||
|
||||
if ($actionCatalogId > 0 && $menuId > 0) {
|
||||
DB::table('admin_menu_actions')->updateOrInsert(
|
||||
['permission_code' => 'system.admin_role.manage'],
|
||||
[
|
||||
'menu_id' => $menuId,
|
||||
'action_id' => $actionCatalogId,
|
||||
'name' => '角色权限管理',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$adminRoleSlug = 'prd.admin_role.manage';
|
||||
$adminUserSlug = 'prd.admin_user.manage';
|
||||
$roleIds = DB::table('admin_role_legacy_permissions')
|
||||
->where('permission_slug', $adminUserSlug)
|
||||
->pluck('role_id')
|
||||
->all();
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_legacy_permissions')->updateOrInsert(
|
||||
[
|
||||
'role_id' => (int) $roleId,
|
||||
'permission_slug' => $adminRoleSlug,
|
||||
],
|
||||
[
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
|
||||
foreach (AdminPermissionBridge::menuActionCodesForLegacy($adminRoleSlug) as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚授权数据,避免删除线上已经显式授予的角色管理权限。
|
||||
}
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$playersMenuId = (int) DB::table('admin_menus')->where('code', 'service.players')->value('id');
|
||||
$updateActionId = (int) DB::table('admin_action_catalog')->where('code', 'update')->value('id');
|
||||
|
||||
if ($playersMenuId > 0 && $updateActionId > 0) {
|
||||
DB::table('admin_menu_actions')->updateOrInsert(
|
||||
['permission_code' => 'service.players.freeze'],
|
||||
[
|
||||
'menu_id' => $playersMenuId,
|
||||
'action_id' => $updateActionId,
|
||||
'name' => '冻结解冻玩家',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$playerResourceBindings = [
|
||||
'admin.players.index' => ['service.players.manage', 'service.players.view'],
|
||||
'admin.players.store' => ['service.players.manage'],
|
||||
'admin.players.show' => ['service.players.manage', 'service.players.view'],
|
||||
'admin.players.update' => ['service.players.manage'],
|
||||
'admin.players.destroy' => ['service.players.manage'],
|
||||
'admin.players.freeze' => ['service.players.freeze'],
|
||||
'admin.players.unfreeze' => ['service.players.freeze'],
|
||||
'admin.players.wallets' => ['service.players.manage', 'service.wallet.view'],
|
||||
'admin.players.ticket-items' => ['service.players.manage', 'service.tickets.view'],
|
||||
];
|
||||
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
if (($resource['module_code'] ?? null) !== 'player_service') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
$permissionCodes = $playerResourceBindings[$resource['code']] ?? $resource['permission_codes'];
|
||||
foreach ($permissionCodes as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚授权绑定,避免误删线上已调整的资源权限关系。
|
||||
}
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.tickets.index')
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId([
|
||||
'code' => 'admin.tickets.index',
|
||||
'module_code' => 'ticket',
|
||||
'name' => '后台注单列表',
|
||||
'http_method' => 'GET',
|
||||
'uri_pattern' => '/api/v1/admin/tickets',
|
||||
'route_name' => 'api.v1.admin.tickets.index',
|
||||
'auth_mode' => 'permission_required',
|
||||
'is_audit_required' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$menuActionId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.tickets.view')
|
||||
->value('id');
|
||||
|
||||
if ($menuActionId !== null) {
|
||||
$exists = DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', $resourceId)
|
||||
->where('menu_action_id', $menuActionId)
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => $resourceId,
|
||||
'menu_action_id' => $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.tickets.index')
|
||||
->value('id');
|
||||
|
||||
if ($resourceId !== null) {
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', $resourceId)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', $resourceId)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.currencies.'),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->join('admin_api_resources as ar', 'ar.id', '=', 'arb.api_resource_id')
|
||||
->whereIn('ar.code', array_column($resources, 'code'))
|
||||
->select('rma.role_id', 'arb.api_resource_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $row->api_resource_id,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceCodes = ['admin.currencies.index', 'admin.currencies.store', 'admin.currencies.update'];
|
||||
|
||||
$resourceIds = DB::table('admin_api_resources')
|
||||
->whereIn('code', $resourceCodes)
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
if ($resourceIds === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_role_api_resources')
|
||||
->whereIn('api_resource_id', $resourceIds)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->whereIn('api_resource_id', $resourceIds)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resources')
|
||||
->whereIn('id', $resourceIds)
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('odds_items', function (Blueprint $table) {
|
||||
// 添加 dimension 字段用于按 2D/3D/4D 配置佣金
|
||||
$table->unsignedTinyInteger('dimension')->nullable()->after('prize_scope')->comment('2/3/4 维度,佣金按维度配置');
|
||||
|
||||
// 删除旧的唯一约束
|
||||
$table->dropUnique('uk_odds_items_version_play_prize_currency');
|
||||
|
||||
// 添加新的唯一约束:佣金按 dimension + currency_code 配置
|
||||
// 赔率仍按 play_code + prize_scope + currency_code 配置
|
||||
$table->unique(
|
||||
['version_id', 'play_code', 'prize_scope', 'currency_code', 'dimension'],
|
||||
'uk_odds_items_version_play_prize_currency_dimension'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('odds_items', function (Blueprint $table) {
|
||||
// 删除新的唯一约束
|
||||
$table->dropUnique('uk_odds_items_version_play_prize_currency_dimension');
|
||||
|
||||
// 恢复旧的唯一约束
|
||||
$table->unique(
|
||||
['version_id', 'play_code', 'prize_scope', 'currency_code'],
|
||||
'uk_odds_items_version_play_prize_currency'
|
||||
);
|
||||
|
||||
// 删除 dimension 字段
|
||||
$table->dropColumn('dimension');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resource = collect(AdminAuthorizationRegistry::resources())
|
||||
->first(static fn (array $item): bool => $item['code'] === 'admin.currencies.destroy');
|
||||
|
||||
if ($resource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->where('arb.api_resource_id', (int) $resourceId)
|
||||
->select('rma.role_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.currencies.destroy')
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_role_api_resources')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,143 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$serviceMenuId = (int) DB::table('admin_menus')->where('code', 'service')->value('id');
|
||||
$manageActionId = (int) DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
|
||||
if ($serviceMenuId > 0) {
|
||||
DB::table('admin_menus')->updateOrInsert(
|
||||
['code' => 'service.currency'],
|
||||
[
|
||||
'parent_id' => $serviceMenuId,
|
||||
'menu_type' => 'page',
|
||||
'name' => '币种管理',
|
||||
'path' => '/admin/settings/currencies',
|
||||
'route_name' => 'admin.settings.currencies',
|
||||
'component' => 'settings/currencies',
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 70,
|
||||
'is_visible' => false,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$currencyMenuId = (int) DB::table('admin_menus')->where('code', 'service.currency')->value('id');
|
||||
if ($currencyMenuId > 0 && $manageActionId > 0) {
|
||||
DB::table('admin_menu_actions')->updateOrInsert(
|
||||
['permission_code' => 'service.currency.manage'],
|
||||
[
|
||||
'menu_id' => $currencyMenuId,
|
||||
'action_id' => $manageActionId,
|
||||
'name' => '币种管理',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_permissions')) {
|
||||
DB::table('admin_permissions')->updateOrInsert(
|
||||
['slug' => 'prd.currency.manage'],
|
||||
[
|
||||
'name' => '币种管理·可管理',
|
||||
'updated_at' => $now,
|
||||
'created_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$currencyActionId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.currency.manage')
|
||||
->value('id');
|
||||
|
||||
if ($currencyActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roleIds = DB::table('admin_role_legacy_permissions')
|
||||
->where('permission_slug', 'prd.users.manage')
|
||||
->pluck('role_id')
|
||||
->all();
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_legacy_permissions')->updateOrInsert(
|
||||
[
|
||||
'role_id' => (int) $roleId,
|
||||
'permission_slug' => 'prd.currency.manage',
|
||||
],
|
||||
[
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert(
|
||||
[
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $currencyActionId,
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
$currencyResourceIds = DB::table('admin_api_resources')
|
||||
->whereIn('code', [
|
||||
'admin.currencies.index',
|
||||
'admin.currencies.store',
|
||||
'admin.currencies.update',
|
||||
'admin.currencies.destroy',
|
||||
])
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
foreach ($currencyResourceIds as $resourceId) {
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $currencyActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->whereIn('arb.api_resource_id', $currencyResourceIds)
|
||||
->select('rma.role_id', 'arb.api_resource_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $row->api_resource_id,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不自动回滚线上角色与资源绑定,避免误删已调整的授权。
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::table('admin_menus')
|
||||
->where('code', 'service.currency')
|
||||
->update([
|
||||
'path' => '/admin/currencies',
|
||||
'route_name' => 'admin.currencies',
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::table('admin_menus')
|
||||
->where('code', 'service.currency')
|
||||
->update([
|
||||
'path' => '/admin/settings/currencies',
|
||||
'route_name' => 'admin.settings.currencies',
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
};
|
||||
@@ -1,160 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$actionViewId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
if ($actionViewId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$serviceMenuId = DB::table('admin_menus')->where('code', 'service')->value('id');
|
||||
if ($serviceMenuId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reportMenuId = DB::table('admin_menus')->where('code', 'service.report')->value('id');
|
||||
if ($reportMenuId === null) {
|
||||
$reportMenuId = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => $serviceMenuId,
|
||||
'menu_type' => 'page',
|
||||
'code' => 'service.report',
|
||||
'name' => '报表中心',
|
||||
'path' => '/admin/reports',
|
||||
'route_name' => 'admin.reports.index',
|
||||
'component' => 'service/reports',
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 50,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
if (! isset($menuActionIds['service.report.view'])) {
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => (int) $reportMenuId,
|
||||
'action_id' => (int) $actionViewId,
|
||||
'permission_code' => 'service.report.view',
|
||||
'name' => '报表中心查看',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
}
|
||||
|
||||
$reportResourceCodes = [
|
||||
'admin.reports.daily-profit',
|
||||
'admin.reports.player-win-loss',
|
||||
'admin.reports.play-dimension',
|
||||
'admin.reports.rebate-commission',
|
||||
'admin.report-jobs.index',
|
||||
'admin.report-jobs.store',
|
||||
'admin.report-jobs.show',
|
||||
'admin.report-jobs.download',
|
||||
];
|
||||
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
if (! in_array($resource['code'], $reportResourceCodes, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
if ($superRoleId !== null && isset($menuActionIds['service.report.view'])) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'menu_action_id' => (int) $menuActionIds['service.report.view'],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = [
|
||||
'admin.reports.daily-profit',
|
||||
'admin.reports.player-win-loss',
|
||||
'admin.reports.play-dimension',
|
||||
'admin.reports.rebate-commission',
|
||||
'admin.report-jobs.index',
|
||||
'admin.report-jobs.store',
|
||||
'admin.report-jobs.show',
|
||||
'admin.report-jobs.download',
|
||||
];
|
||||
|
||||
$resourceIds = DB::table('admin_api_resources')->whereIn('code', $codes)->pluck('id');
|
||||
foreach ($resourceIds as $resourceId) {
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
|
||||
$menuActionId = DB::table('admin_menu_actions')->where('permission_code', 'service.report.view')->value('id');
|
||||
if ($menuActionId !== null) {
|
||||
DB::table('admin_role_menu_actions')->where('menu_action_id', (int) $menuActionId)->delete();
|
||||
DB::table('admin_menu_actions')->where('id', (int) $menuActionId)->delete();
|
||||
}
|
||||
|
||||
DB::table('admin_menus')->where('code', 'service.report')->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,122 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const STALE_RESOURCE_CODES = [
|
||||
'admin.reports.index',
|
||||
'admin.reports.store',
|
||||
'admin.reconcile.index',
|
||||
'admin.reconcile.store',
|
||||
'admin.draws.publish',
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
private const REPORT_RESOURCE_CODES = [
|
||||
'admin.reports.daily-profit',
|
||||
'admin.reports.player-win-loss',
|
||||
'admin.reports.play-dimension',
|
||||
'admin.reports.rebate-commission',
|
||||
'admin.report-jobs.index',
|
||||
'admin.report-jobs.store',
|
||||
'admin.report-jobs.show',
|
||||
'admin.report-jobs.download',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$this->deleteStaleApiResources();
|
||||
$this->ensureReportViewOnRolesWithReportLegacy();
|
||||
$this->syncReportResourceBindings($now);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 绑定收紧与角色补权为数据修复,不回滚以免再现漂移。
|
||||
}
|
||||
|
||||
private function deleteStaleApiResources(): void
|
||||
{
|
||||
$resourceIds = DB::table('admin_api_resources')
|
||||
->whereIn('code', self::STALE_RESOURCE_CODES)
|
||||
->pluck('id');
|
||||
|
||||
foreach ($resourceIds as $resourceId) {
|
||||
$id = (int) $resourceId;
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', $id)->delete();
|
||||
DB::table('admin_api_resources')->where('id', $id)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureReportViewOnRolesWithReportLegacy(): void
|
||||
{
|
||||
$menuActionId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.report.view')
|
||||
->where('status', 1)
|
||||
->value('id');
|
||||
|
||||
if ($menuActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reportSlugs = ['prd.report.view', 'prd.report.all', 'prd.report.risk', 'prd.report.finance', 'prd.report.player'];
|
||||
$roleIds = DB::table('admin_role_legacy_permissions')
|
||||
->whereIn('permission_slug', $reportSlugs)
|
||||
->distinct()
|
||||
->pluck('role_id');
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function syncReportResourceBindings(Carbon $now): void
|
||||
{
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$registryByCode = [];
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
$registryByCode[$resource['code']] = $resource;
|
||||
}
|
||||
|
||||
foreach (self::REPORT_RESOURCE_CODES as $code) {
|
||||
$resource = $registryByCode[$code] ?? null;
|
||||
if ($resource === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $code)->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 移除未接入业务或已由其它表替代的冗余表:
|
||||
* - system_jobs:从未使用
|
||||
* - admin_role_menus:侧栏改由 prd.* + Registry 驱动
|
||||
* - admin_role_api_resources:鉴权由 role_menu_actions + bindings 实时推导
|
||||
* - admin_*_data_scopes:数据范围未落地
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_user_data_scopes');
|
||||
Schema::dropIfExists('admin_role_data_scopes');
|
||||
Schema::dropIfExists('admin_data_scopes');
|
||||
Schema::dropIfExists('admin_role_api_resources');
|
||||
Schema::dropIfExists('admin_role_menus');
|
||||
Schema::dropIfExists('system_jobs');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 冗余表删除为单向清理,不回滚。
|
||||
}
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\AdminRole;
|
||||
use App\Support\AdminPermissionBridge;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('admin_role_legacy_permissions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roleIds = DB::table('admin_roles')->pluck('id');
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
$legacySlugs = DB::table('admin_role_legacy_permissions')
|
||||
->where('role_id', (int) $roleId)
|
||||
->pluck('permission_slug')
|
||||
->all();
|
||||
|
||||
$slugs = AdminPermissionBridge::normalizeCanonicalLegacySlugs(
|
||||
is_array($legacySlugs) ? $legacySlugs : [],
|
||||
);
|
||||
|
||||
if ($slugs === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$role = AdminRole::query()->find((int) $roleId);
|
||||
if ($role !== null) {
|
||||
$role->syncLegacyPermissionSlugs($slugs);
|
||||
}
|
||||
}
|
||||
|
||||
Schema::dropIfExists('admin_role_legacy_permissions');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 单向清理:slug 已合并,权限以 admin_role_menu_actions 为准。
|
||||
}
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\LotterySetting;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 玩法规则 HTML:由单键 frontend.play_rules_html 拆分为 zh/en/ne 三语键。
|
||||
* 已有内容迁移到 frontend.play_rules_html_zh。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
private const LEGACY_KEY = 'frontend.play_rules_html';
|
||||
|
||||
private const I18N_KEYS = [
|
||||
'frontend.play_rules_html_zh' => '玩家端玩法规则页 HTML(中文)',
|
||||
'frontend.play_rules_html_en' => '玩家端玩法规则页 HTML(English)',
|
||||
'frontend.play_rules_html_ne' => '玩家端玩法规则页 HTML(नेपाली)',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$legacyRow = LotterySetting::query()->where('setting_key', self::LEGACY_KEY)->first();
|
||||
$legacyValue = $legacyRow?->value_json;
|
||||
|
||||
foreach (self::I18N_KEYS as $key => $description) {
|
||||
if (LotterySetting::query()->where('setting_key', $key)->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = '';
|
||||
if ($key === 'frontend.play_rules_html_zh' && is_string($legacyValue) && trim($legacyValue) !== '') {
|
||||
$value = $legacyValue;
|
||||
}
|
||||
|
||||
LotterySetting::query()->create([
|
||||
'setting_key' => $key,
|
||||
'value_json' => $value,
|
||||
'group_name' => 'frontend',
|
||||
'description_zh' => $description,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
LotterySetting::query()
|
||||
->whereIn('setting_key', array_keys(self::I18N_KEYS))
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
foreach (['play_types', 'play_config_items'] as $table) {
|
||||
Schema::table($table, function (Blueprint $blueprint): void {
|
||||
$blueprint->string('display_name', 64)->nullable()->after('bet_mode');
|
||||
});
|
||||
|
||||
DB::table($table)->update([
|
||||
'display_name' => DB::raw(
|
||||
"COALESCE(
|
||||
NULLIF(TRIM(display_name_zh), ''),
|
||||
NULLIF(TRIM(display_name_en), ''),
|
||||
NULLIF(TRIM(display_name_ne), ''),
|
||||
play_code
|
||||
)",
|
||||
),
|
||||
]);
|
||||
|
||||
Schema::table($table, function (Blueprint $blueprint): void {
|
||||
$blueprint->dropColumn(['display_name_zh', 'display_name_en', 'display_name_ne']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (['play_types', 'play_config_items'] as $table) {
|
||||
Schema::table($table, function (Blueprint $blueprint): void {
|
||||
$blueprint->string('display_name_zh', 64)->nullable()->after('bet_mode');
|
||||
$blueprint->string('display_name_en', 64)->nullable()->after('display_name_zh');
|
||||
$blueprint->string('display_name_ne', 64)->nullable()->after('display_name_en');
|
||||
});
|
||||
|
||||
DB::table($table)->update([
|
||||
'display_name_zh' => DB::raw('display_name'),
|
||||
'display_name_en' => DB::raw('display_name'),
|
||||
'display_name_ne' => DB::raw('display_name'),
|
||||
]);
|
||||
|
||||
Schema::table($table, function (Blueprint $blueprint): void {
|
||||
$blueprint->dropColumn('display_name');
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* admin_api_resources.code 最长可达 128;中间件将完整 code 写入 audit_logs.target_type。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('audit_logs', function (Blueprint $table): void {
|
||||
$table->string('target_type', 128)->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('audit_logs', function (Blueprint $table): void {
|
||||
$table->string('target_type', 32)->nullable()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$actionIds = DB::table('admin_action_catalog')->pluck('id', 'code');
|
||||
$menuIds = DB::table('admin_menus')->pluck('id', 'code');
|
||||
|
||||
$walletMenuId = $menuIds['service.wallet'] ?? null;
|
||||
$updateActionId = $actionIds['update'] ?? null;
|
||||
if ($walletMenuId !== null && $updateActionId !== null) {
|
||||
$exists = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.wallet.adjust')
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => $walletMenuId,
|
||||
'action_id' => $updateActionId,
|
||||
'permission_code' => 'service.wallet.adjust',
|
||||
'name' => '钱包补单/冲正',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$oddsMenuId = $menuIds['config.odds'] ?? null;
|
||||
$viewActionId = $actionIds['view'] ?? null;
|
||||
if ($oddsMenuId !== null && $viewActionId !== null) {
|
||||
$exists = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'config.odds.view')
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => $oddsMenuId,
|
||||
'action_id' => $viewActionId,
|
||||
'permission_code' => 'config.odds.view',
|
||||
'name' => '赔率配置查看',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', ['service.wallet.adjust', 'config.odds.view'])
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const STALE_PERMISSION_CODES = [
|
||||
'dashboard.view',
|
||||
'service.reports.view',
|
||||
'service.reports.export',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$menuActionIds = DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', self::STALE_PERMISSION_CODES)
|
||||
->pluck('id');
|
||||
|
||||
if ($menuActionIds->isNotEmpty()) {
|
||||
DB::table('admin_menu_actions')
|
||||
->whereIn('id', $menuActionIds->all())
|
||||
->delete();
|
||||
}
|
||||
|
||||
$staleReportMenuId = DB::table('admin_menus')
|
||||
->where('code', 'service.reports')
|
||||
->value('id');
|
||||
|
||||
if ($staleReportMenuId !== null) {
|
||||
$hasActions = DB::table('admin_menu_actions')
|
||||
->where('menu_id', (int) $staleReportMenuId)
|
||||
->exists();
|
||||
|
||||
if (! $hasActions) {
|
||||
DB::table('admin_menus')
|
||||
->where('id', (int) $staleReportMenuId)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 数据清理迁移,不回滚以免再现僵尸 permission_code。
|
||||
}
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$resource = collect(AdminAuthorizationRegistry::resources())
|
||||
->firstWhere('code', 'admin.dashboard.analytics');
|
||||
|
||||
if ($resource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.dashboard.analytics')
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => 'admin.dashboard.analytics',
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$actionId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', $permissionCode)
|
||||
->value('id');
|
||||
if ($actionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $actionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.dashboard.analytics')
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('settlement_batches', function (Blueprint $table): void {
|
||||
if (! Schema::hasColumn('settlement_batches', 'review_status')) {
|
||||
$table->string('review_status', 32)->default('pending')->after('total_jackpot_payout_amount');
|
||||
}
|
||||
if (! Schema::hasColumn('settlement_batches', 'reviewed_by')) {
|
||||
$table->foreignId('reviewed_by')->nullable()->after('review_status')->constrained('admin_users')->nullOnDelete();
|
||||
}
|
||||
if (! Schema::hasColumn('settlement_batches', 'reviewed_at')) {
|
||||
$table->timestamp('reviewed_at')->nullable()->after('reviewed_by');
|
||||
}
|
||||
if (! Schema::hasColumn('settlement_batches', 'review_remark')) {
|
||||
$table->string('review_remark', 255)->nullable()->after('reviewed_at');
|
||||
}
|
||||
if (! Schema::hasColumn('settlement_batches', 'paid_at')) {
|
||||
$table->timestamp('paid_at')->nullable()->after('review_remark');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('settlement_batches', function (Blueprint $table): void {
|
||||
if (Schema::hasColumn('settlement_batches', 'paid_at')) {
|
||||
$table->dropColumn('paid_at');
|
||||
}
|
||||
if (Schema::hasColumn('settlement_batches', 'review_remark')) {
|
||||
$table->dropColumn('review_remark');
|
||||
}
|
||||
if (Schema::hasColumn('settlement_batches', 'reviewed_at')) {
|
||||
$table->dropColumn('reviewed_at');
|
||||
}
|
||||
if (Schema::hasColumn('settlement_batches', 'reviewed_by')) {
|
||||
$table->dropForeign(['reviewed_by']);
|
||||
$table->dropColumn('reviewed_by');
|
||||
}
|
||||
if (Schema::hasColumn('settlement_batches', 'review_status')) {
|
||||
$table->dropColumn('review_status');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,216 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminPermissionBridge;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<array{menu_code: string, action_code: string, permission_code: string, name: string}> */
|
||||
private const NEW_MENU_ACTIONS = [
|
||||
['menu_code' => 'dashboard', 'action_code' => 'view', 'permission_code' => 'dashboard.view', 'name' => '仪表盘查看'],
|
||||
['menu_code' => 'service.report', 'action_code' => 'export', 'permission_code' => 'service.report.export', 'name' => '报表导出'],
|
||||
['menu_code' => 'risk.monitor', 'action_code' => 'manage', 'permission_code' => 'risk.monitor.manage', 'name' => '风控监控管理'],
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuIds = DB::table('admin_menus')->pluck('id', 'code');
|
||||
$actionIds = DB::table('admin_action_catalog')->pluck('id', 'code');
|
||||
|
||||
$menuActionIds = [];
|
||||
foreach (self::NEW_MENU_ACTIONS as $row) {
|
||||
$menuId = $menuIds[$row['menu_code']] ?? null;
|
||||
$actionId = $actionIds[$row['action_code']] ?? null;
|
||||
if ($menuId === null || $actionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$exists = DB::table('admin_menu_actions')
|
||||
->where('permission_code', $row['permission_code'])
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
$menuActionIds[$row['permission_code']] = (int) DB::table('admin_menu_actions')
|
||||
->where('permission_code', $row['permission_code'])
|
||||
->value('id');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$menuActionIds[$row['permission_code']] = (int) DB::table('admin_menu_actions')->insertGetId([
|
||||
'menu_id' => (int) $menuId,
|
||||
'action_id' => (int) $actionId,
|
||||
'permission_code' => $row['permission_code'],
|
||||
'name' => $row['name'],
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->grantMenuActionsToAllRoles($menuActionIds, $now);
|
||||
$this->grantReportExportToReportViewRoles($menuActionIds['service.report.export'] ?? null, $now);
|
||||
$this->grantTicketsViewToLegacyRoles($menuActionIds, $now);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = array_column(self::NEW_MENU_ACTIONS, 'permission_code');
|
||||
$ids = DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->pluck('id');
|
||||
foreach ($ids as $id) {
|
||||
DB::table('admin_role_menu_actions')->where('menu_action_id', (int) $id)->delete();
|
||||
DB::table('admin_user_menu_actions')->where('menu_action_id', (int) $id)->delete();
|
||||
DB::table('admin_api_resource_bindings')->where('menu_action_id', (int) $id)->delete();
|
||||
DB::table('admin_menu_actions')->where('id', (int) $id)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, int> $menuActionIds
|
||||
*/
|
||||
private function grantMenuActionsToAllRoles(array $menuActionIds, Carbon $now): void
|
||||
{
|
||||
$dashboardId = $menuActionIds['dashboard.view'] ?? null;
|
||||
if ($dashboardId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roleIds = DB::table('admin_roles')->pluck('id');
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => $dashboardId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function grantReportExportToReportViewRoles(?int $exportMenuActionId, Carbon $now): void
|
||||
{
|
||||
if ($exportMenuActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$viewMenuActionId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.report.view')
|
||||
->value('id');
|
||||
|
||||
if ($viewMenuActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roleIds = DB::table('admin_role_menu_actions')
|
||||
->where('menu_action_id', (int) $viewMenuActionId)
|
||||
->distinct()
|
||||
->pluck('role_id');
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => $exportMenuActionId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 原注单入口依赖多种 prd.*;迁移为独立的 prd.tickets.view。
|
||||
*
|
||||
* @param array<string, int> $menuActionIds
|
||||
*/
|
||||
private function grantTicketsViewToLegacyRoles(array $menuActionIds, Carbon $now): void
|
||||
{
|
||||
$ticketsViewId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'service.tickets.view')
|
||||
->value('id');
|
||||
|
||||
if ($ticketsViewId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$legacySlugs = [
|
||||
'prd.users.view_cs',
|
||||
'prd.users.manage',
|
||||
'prd.users.view_finance',
|
||||
'prd.draw_result.view',
|
||||
'prd.draw_result.manage',
|
||||
'prd.payout.view',
|
||||
'prd.payout.review',
|
||||
'prd.payout.manage',
|
||||
];
|
||||
|
||||
$roleIds = $this->roleIdsWithAnyLegacySlug($legacySlugs);
|
||||
|
||||
foreach ($roleIds as $roleId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $ticketsViewId,
|
||||
]);
|
||||
}
|
||||
|
||||
$riskViewId = DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'risk.monitor.view')
|
||||
->value('id');
|
||||
$riskManageId = $menuActionIds['risk.monitor.manage'] ?? null;
|
||||
|
||||
if ($riskManageId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$riskRoleIds = $this->roleIdsWithAnyLegacySlug([
|
||||
'prd.draw_result.manage',
|
||||
'prd.draw_result.view',
|
||||
'prd.risk.manage',
|
||||
'prd.risk.view',
|
||||
]);
|
||||
|
||||
foreach ($riskRoleIds as $roleId) {
|
||||
if ($riskViewId !== null) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $riskViewId,
|
||||
]);
|
||||
}
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $roleId,
|
||||
'menu_action_id' => (int) $riskManageId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过角色已授权的 menu_action 反推曾拥有指定 prd.* 的角色(legacy 表已废弃)。
|
||||
*
|
||||
* @param list<string> $legacySlugs
|
||||
* @return list<int>
|
||||
*/
|
||||
private function roleIdsWithAnyLegacySlug(array $legacySlugs): array
|
||||
{
|
||||
$codes = [];
|
||||
foreach ($legacySlugs as $slug) {
|
||||
$codes = array_merge($codes, AdminPermissionBridge::menuActionCodesForLegacy($slug));
|
||||
}
|
||||
$codes = array_values(array_unique($codes));
|
||||
|
||||
if ($codes === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', $codes)
|
||||
->where('status', 1)
|
||||
->pluck('id');
|
||||
|
||||
if ($menuActionIds->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return DB::table('admin_role_menu_actions')
|
||||
->whereIn('menu_action_id', $menuActionIds->map(fn ($id) => (int) $id)->all())
|
||||
->distinct()
|
||||
->pluck('role_id')
|
||||
->map(fn ($id) => (int) $id)
|
||||
->all();
|
||||
}
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->unique(
|
||||
['player_id', 'draw_id', 'client_trace_id'],
|
||||
'uniq_ticket_orders_player_draw_trace',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->dropUnique('uniq_ticket_orders_player_draw_trace');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
if (! DB::table('admin_action_catalog')->where('code', 'manual_burst')->exists()) {
|
||||
DB::table('admin_action_catalog')->insert([
|
||||
'code' => 'manual_burst',
|
||||
'name' => '手动爆池',
|
||||
'sort_order' => 85,
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$jackpotMenuId = (int) DB::table('admin_menus')->where('code', 'config.jackpot')->value('id');
|
||||
$manualBurstActionId = (int) DB::table('admin_action_catalog')->where('code', 'manual_burst')->value('id');
|
||||
|
||||
if ($jackpotMenuId <= 0 || $manualBurstActionId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->updateOrInsert(
|
||||
['permission_code' => 'jackpot.pool.manual_burst'],
|
||||
[
|
||||
'menu_id' => $jackpotMenuId,
|
||||
'action_id' => $manualBurstActionId,
|
||||
'name' => 'Jackpot 手动爆池',
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
|
||||
if (Schema::hasTable('admin_permissions')) {
|
||||
DB::table('admin_permissions')->updateOrInsert(
|
||||
['slug' => 'prd.jackpot.manual_burst'],
|
||||
[
|
||||
'name' => 'Jackpot 手动爆池·仅超管',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$menuActionId = (int) DB::table('admin_menu_actions')
|
||||
->where('permission_code', 'jackpot.pool.manual_burst')
|
||||
->value('id');
|
||||
|
||||
$superRoleId = (int) DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
if ($superRoleId > 0 && $menuActionId > 0) {
|
||||
if (Schema::hasTable('admin_role_legacy_permissions')) {
|
||||
DB::table('admin_role_legacy_permissions')->updateOrInsert(
|
||||
[
|
||||
'role_id' => $superRoleId,
|
||||
'permission_slug' => 'prd.jackpot.manual_burst',
|
||||
],
|
||||
[
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert(
|
||||
[
|
||||
'role_id' => $superRoleId,
|
||||
'menu_action_id' => $menuActionId,
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', 'admin.jackpot.pools.manual-burst')
|
||||
->value('id');
|
||||
|
||||
if ($resourceId !== null && $menuActionId > 0) {
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
if ($superRoleId > 0 && Schema::hasTable('admin_role_api_resources')) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => $superRoleId,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 避免误删线上已调整的授权绑定。
|
||||
}
|
||||
};
|
||||
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_sites', function (Blueprint $table): void {
|
||||
$table->string('wallet_api_url', 512)->nullable()->after('extra_json');
|
||||
$table->string('wallet_debit_path', 128)->default('/wallet/debit-for-lottery')->after('wallet_api_url');
|
||||
$table->string('wallet_credit_path', 128)->default('/wallet/credit-from-lottery')->after('wallet_debit_path');
|
||||
$table->string('wallet_balance_path', 128)->default('/wallet/balance')->after('wallet_credit_path');
|
||||
$table->text('wallet_api_key_encrypted')->nullable()->after('wallet_balance_path');
|
||||
$table->text('sso_jwt_secret_encrypted')->nullable()->after('wallet_api_key_encrypted');
|
||||
$table->unsignedSmallInteger('wallet_timeout_seconds')->default(10)->after('sso_jwt_secret_encrypted');
|
||||
$table->json('iframe_allowed_origins')->nullable()->after('wallet_timeout_seconds');
|
||||
$table->string('lottery_h5_base_url', 512)->nullable()->after('iframe_allowed_origins');
|
||||
$table->text('notes')->nullable()->after('lottery_h5_base_url');
|
||||
});
|
||||
|
||||
$this->seedIntegrationMenuActions();
|
||||
$this->backfillDefaultSiteFromEnv();
|
||||
$this->syncIntegrationApiResources();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceIds = DB::table('admin_api_resources')
|
||||
->where('code', 'like', 'admin.integration-sites.%')
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
if ($resourceIds !== []) {
|
||||
DB::table('admin_role_api_resources')->whereIn('api_resource_id', $resourceIds)->delete();
|
||||
DB::table('admin_api_resource_bindings')->whereIn('api_resource_id', $resourceIds)->delete();
|
||||
DB::table('admin_api_resources')->whereIn('id', $resourceIds)->delete();
|
||||
}
|
||||
|
||||
Schema::table('admin_sites', function (Blueprint $table): void {
|
||||
$table->dropColumn([
|
||||
'wallet_api_url',
|
||||
'wallet_debit_path',
|
||||
'wallet_credit_path',
|
||||
'wallet_balance_path',
|
||||
'wallet_api_key_encrypted',
|
||||
'sso_jwt_secret_encrypted',
|
||||
'wallet_timeout_seconds',
|
||||
'iframe_allowed_origins',
|
||||
'lottery_h5_base_url',
|
||||
'notes',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function seedIntegrationMenuActions(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$viewActionId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
$manageActionId = DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
if ($viewActionId === null || $manageActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configMenuId = DB::table('admin_menus')->where('code', 'config')->value('id');
|
||||
if ($configMenuId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$integrationMenuId = DB::table('admin_menus')->where('code', 'config.integration')->value('id');
|
||||
if ($integrationMenuId === null) {
|
||||
$integrationMenuId = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => (int) $configMenuId,
|
||||
'menu_type' => 'page',
|
||||
'code' => 'config.integration',
|
||||
'name' => '主站接入站点',
|
||||
'path' => '/admin/config/integration-sites',
|
||||
'route_name' => 'admin.config.integration',
|
||||
'component' => 'config/integration',
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 45,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ([
|
||||
['permission_code' => 'integration.site.view', 'action_id' => (int) $viewActionId, 'name' => '接入站点查看'],
|
||||
['permission_code' => 'integration.site.manage', 'action_id' => (int) $manageActionId, 'name' => '接入站点管理'],
|
||||
] as $row) {
|
||||
$exists = DB::table('admin_menu_actions')
|
||||
->where('permission_code', $row['permission_code'])
|
||||
->exists();
|
||||
if ($exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => (int) $integrationMenuId,
|
||||
'action_id' => $row['action_id'],
|
||||
'permission_code' => $row['permission_code'],
|
||||
'name' => $row['name'],
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function backfillDefaultSiteFromEnv(): void
|
||||
{
|
||||
$siteId = DB::table('admin_sites')->where('is_default', true)->value('id')
|
||||
?? DB::table('admin_sites')->orderBy('id')->value('id');
|
||||
|
||||
if ($siteId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$walletUrl = env('MAIN_SITE_WALLET_API_URL');
|
||||
$ssoSecret = env('MAIN_SITE_SSO_JWT_SECRET');
|
||||
$walletKey = env('MAIN_SITE_WALLET_API_KEY');
|
||||
|
||||
$payload = [
|
||||
'updated_at' => Carbon::now(),
|
||||
];
|
||||
|
||||
if (is_string($walletUrl) && trim($walletUrl) !== '') {
|
||||
$payload['wallet_api_url'] = rtrim(trim($walletUrl), '/');
|
||||
}
|
||||
|
||||
$debitPath = env('MAIN_SITE_WALLET_DEBIT_PATH');
|
||||
if (is_string($debitPath) && $debitPath !== '') {
|
||||
$payload['wallet_debit_path'] = $debitPath;
|
||||
}
|
||||
|
||||
$creditPath = env('MAIN_SITE_WALLET_CREDIT_PATH');
|
||||
if (is_string($creditPath) && $creditPath !== '') {
|
||||
$payload['wallet_credit_path'] = $creditPath;
|
||||
}
|
||||
|
||||
$balancePath = env('MAIN_SITE_WALLET_BALANCE_PATH');
|
||||
if (is_string($balancePath) && $balancePath !== '') {
|
||||
$payload['wallet_balance_path'] = $balancePath;
|
||||
}
|
||||
|
||||
$timeout = env('MAIN_SITE_WALLET_TIMEOUT');
|
||||
if (is_numeric($timeout)) {
|
||||
$payload['wallet_timeout_seconds'] = max(1, (int) $timeout);
|
||||
}
|
||||
|
||||
if (is_string($ssoSecret) && $ssoSecret !== '') {
|
||||
$payload['sso_jwt_secret_encrypted'] = encrypt($ssoSecret);
|
||||
}
|
||||
|
||||
if (is_string($walletKey) && $walletKey !== '') {
|
||||
$payload['wallet_api_key_encrypted'] = encrypt($walletKey);
|
||||
}
|
||||
|
||||
if (count($payload) > 1) {
|
||||
DB::table('admin_sites')->where('id', (int) $siteId)->update($payload);
|
||||
}
|
||||
}
|
||||
|
||||
private function syncIntegrationApiResources(): void
|
||||
{
|
||||
if (! Schema::hasTable('admin_api_resources')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.integration-sites.'),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 为已执行 140000 的环境补种 integration 权限动作并同步 API 绑定。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$viewActionId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
$manageActionId = DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
if ($viewActionId === null || $manageActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$configMenuId = DB::table('admin_menus')->where('code', 'config')->value('id');
|
||||
if ($configMenuId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$integrationMenuId = DB::table('admin_menus')->where('code', 'config.integration')->value('id');
|
||||
if ($integrationMenuId === null) {
|
||||
$integrationMenuId = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => (int) $configMenuId,
|
||||
'menu_type' => 'page',
|
||||
'code' => 'config.integration',
|
||||
'name' => '主站接入站点',
|
||||
'path' => '/admin/config/integration-sites',
|
||||
'route_name' => 'admin.config.integration',
|
||||
'component' => 'config/integration',
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 45,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ([
|
||||
['permission_code' => 'integration.site.view', 'action_id' => (int) $viewActionId, 'name' => '接入站点查看'],
|
||||
['permission_code' => 'integration.site.manage', 'action_id' => (int) $manageActionId, 'name' => '接入站点管理'],
|
||||
] as $row) {
|
||||
if (DB::table('admin_menu_actions')->where('permission_code', $row['permission_code'])->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => (int) $integrationMenuId,
|
||||
'action_id' => $row['action_id'],
|
||||
'permission_code' => $row['permission_code'],
|
||||
'name' => $row['name'],
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.integration-sites.'),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 保留 menu_actions / bindings,避免回滚后超管无法管理已创建的接入站点。
|
||||
}
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* `dashboard.view` 在 2026_05_26 才写入 admin_menu_actions,此前 sync 无法绑定
|
||||
* admin.dashboard / admin.dashboard.analytics,导致 permission_required 资源无 bindings。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 数据修复迁移:不在 down 中回滚 bindings,避免误删线上授权关系。
|
||||
}
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$duplicateIds = DB::table('jackpot_contributions')
|
||||
->select('ticket_item_id')
|
||||
->whereNotNull('ticket_item_id')
|
||||
->groupBy('ticket_item_id')
|
||||
->havingRaw('count(*) > 1')
|
||||
->pluck('ticket_item_id');
|
||||
|
||||
foreach ($duplicateIds as $ticketItemId) {
|
||||
$rows = DB::table('jackpot_contributions')
|
||||
->where('ticket_item_id', $ticketItemId)
|
||||
->orderByDesc('id')
|
||||
->pluck('id');
|
||||
$keep = $rows->shift();
|
||||
if ($keep !== null && $rows->isNotEmpty()) {
|
||||
DB::table('jackpot_contributions')->whereIn('id', $rows->all())->delete();
|
||||
}
|
||||
}
|
||||
|
||||
Schema::table('jackpot_contributions', function (Blueprint $table): void {
|
||||
$table->unique('ticket_item_id', 'uk_jackpot_contributions_ticket_item');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('jackpot_contributions', function (Blueprint $table): void {
|
||||
$table->dropUnique('uk_jackpot_contributions_ticket_item');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jackpot_pool_adjustments', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('adjustment_no', 32)->unique();
|
||||
$table->foreignId('jackpot_pool_id')->constrained('jackpot_pools')->cascadeOnDelete();
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->bigInteger('amount_delta')->comment('signed minor units; + increase pool');
|
||||
$table->bigInteger('balance_before');
|
||||
$table->bigInteger('balance_after');
|
||||
$table->string('reason', 500);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['jackpot_pool_id', 'created_at'], 'idx_jackpot_pool_adjustments_pool_created');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jackpot_pool_adjustments');
|
||||
}
|
||||
};
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const RESOURCE_CODES = [
|
||||
'admin.jackpot.pools.adjustments.index',
|
||||
'admin.jackpot.pools.adjustments.store',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$resources = collect(AdminAuthorizationRegistry::resources())
|
||||
->filter(fn (array $item): bool => in_array($item['code'], self::RESOURCE_CODES, true))
|
||||
->values();
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->where('arb.api_resource_id', (int) $resourceId)
|
||||
->select('rma.role_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (self::RESOURCE_CODES as $code) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $code)->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
DB::table('admin_role_api_resources')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
}
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 对齐高频查询路径(PostgreSQL B-tree)。
|
||||
*
|
||||
* - ticket_orders:按 draw_id 结算/后台汇总
|
||||
* - wallet_txns / ticket_items:player_id + ORDER BY id DESC 分页
|
||||
* - draws:business_date 筛选 + draw_time 排序(往期/报表)
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->index('draw_id', 'idx_ticket_orders_draw_id');
|
||||
});
|
||||
|
||||
Schema::table('wallet_txns', function (Blueprint $table): void {
|
||||
$table->index(['player_id', 'id'], 'idx_wallet_txns_player_id');
|
||||
});
|
||||
|
||||
Schema::table('ticket_items', function (Blueprint $table): void {
|
||||
$table->index(['player_id', 'id'], 'idx_ticket_items_player_id');
|
||||
});
|
||||
|
||||
Schema::table('draws', function (Blueprint $table): void {
|
||||
$table->index(['business_date', 'draw_time'], 'idx_draws_business_date_draw_time');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('draws', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_draws_business_date_draw_time');
|
||||
});
|
||||
|
||||
Schema::table('ticket_items', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_ticket_items_player_id');
|
||||
});
|
||||
|
||||
Schema::table('wallet_txns', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_wallet_txns_player_id');
|
||||
});
|
||||
|
||||
Schema::table('ticket_orders', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_ticket_orders_draw_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
private const RESOURCE_CODE = 'admin.settings.batch-update';
|
||||
|
||||
private const CLONE_BINDINGS_FROM = 'admin.settings.update';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$resource = collect(AdminAuthorizationRegistry::resources())
|
||||
->first(fn (array $item): bool => $item['code'] === self::RESOURCE_CODE);
|
||||
|
||||
if ($resource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
$sourceResourceId = DB::table('admin_api_resources')
|
||||
->where('code', self::CLONE_BINDINGS_FROM)
|
||||
->value('id');
|
||||
|
||||
if ($sourceResourceId !== null) {
|
||||
$bindings = DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $sourceResourceId)
|
||||
->get(['menu_action_id']);
|
||||
|
||||
foreach ($bindings as $binding) {
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $binding->menu_action_id,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
$roleResourceRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->where('arb.api_resource_id', (int) $resourceId)
|
||||
->select('rma.role_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
foreach ($roleResourceRows as $row) {
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $row->role_id,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', self::RESOURCE_CODE)->value('id');
|
||||
if ($resourceId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
DB::table('admin_role_api_resources')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
}
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('agent_nodes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('admin_site_id')->constrained('admin_sites')->cascadeOnDelete();
|
||||
$table->foreignId('parent_id')->nullable()->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->string('path', 512);
|
||||
$table->unsignedSmallInteger('depth')->default(0);
|
||||
$table->string('code', 64);
|
||||
$table->string('name', 128);
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('1=enabled,0=disabled');
|
||||
$table->foreignId('created_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->json('extra_json')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['admin_site_id', 'code'], 'uk_agent_nodes_site_code');
|
||||
$table->index(['admin_site_id', 'parent_id'], 'idx_agent_nodes_site_parent');
|
||||
$table->index('path', 'idx_agent_nodes_path');
|
||||
});
|
||||
|
||||
Schema::create('admin_user_agents', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->primary()->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('agent_node_id')->constrained('agent_nodes')->cascadeOnDelete();
|
||||
$table->boolean('is_primary')->default(true);
|
||||
$table->timestamp('granted_at')->nullable();
|
||||
});
|
||||
|
||||
$this->seedRootAgentNodes();
|
||||
$this->backfillAdminUserAgents();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_user_agents');
|
||||
Schema::dropIfExists('agent_nodes');
|
||||
}
|
||||
|
||||
private function seedRootAgentNodes(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$sites = DB::table('admin_sites')->orderBy('id')->get(['id', 'code', 'name']);
|
||||
|
||||
foreach ($sites as $site) {
|
||||
if (DB::table('agent_nodes')->where('admin_site_id', (int) $site->id)->where('depth', 0)->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$code = 'root-'.(string) $site->code;
|
||||
$nodeId = DB::table('agent_nodes')->insertGetId([
|
||||
'admin_site_id' => (int) $site->id,
|
||||
'parent_id' => null,
|
||||
'path' => '/',
|
||||
'depth' => 0,
|
||||
'code' => $code,
|
||||
'name' => (string) $site->name,
|
||||
'status' => 1,
|
||||
'created_by' => null,
|
||||
'extra_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
DB::table('agent_nodes')->where('id', $nodeId)->update([
|
||||
'path' => '/'.$nodeId.'/',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function backfillAdminUserAgents(): void
|
||||
{
|
||||
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
$now = Carbon::now();
|
||||
|
||||
$userIds = DB::table('admin_users')->pluck('id');
|
||||
foreach ($userIds as $userId) {
|
||||
$userId = (int) $userId;
|
||||
if (DB::table('admin_user_agents')->where('admin_user_id', $userId)->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($superRoleId !== null) {
|
||||
$isSuper = DB::table('admin_user_site_roles')
|
||||
->where('admin_user_id', $userId)
|
||||
->where('role_id', (int) $superRoleId)
|
||||
->exists();
|
||||
if ($isSuper) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$siteId = DB::table('admin_user_site_roles')
|
||||
->where('admin_user_id', $userId)
|
||||
->orderBy('site_id')
|
||||
->value('site_id');
|
||||
|
||||
if ($siteId === null) {
|
||||
$siteId = DB::table('admin_sites')->where('is_default', true)->value('id')
|
||||
?? DB::table('admin_sites')->orderBy('id')->value('id');
|
||||
}
|
||||
|
||||
if ($siteId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rootId = DB::table('agent_nodes')
|
||||
->where('admin_site_id', (int) $siteId)
|
||||
->where('depth', 0)
|
||||
->value('id');
|
||||
|
||||
if ($rootId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_user_agents')->insert([
|
||||
'admin_user_id' => $userId,
|
||||
'agent_node_id' => (int) $rootId,
|
||||
'is_primary' => true,
|
||||
'granted_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,195 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$viewActionId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
$manageActionId = DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
if ($viewActionId === null || $manageActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$systemMenuId = DB::table('admin_menus')->where('code', 'system')->value('id');
|
||||
if ($systemMenuId === null) {
|
||||
$systemMenuId = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => null,
|
||||
'menu_type' => 'directory',
|
||||
'code' => 'system',
|
||||
'name' => '系统',
|
||||
'path' => null,
|
||||
'route_name' => null,
|
||||
'component' => null,
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 90,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$agentMenuId = DB::table('admin_menus')->where('code', 'system.agents')->value('id');
|
||||
if ($agentMenuId === null) {
|
||||
$agentMenuId = DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => (int) $systemMenuId,
|
||||
'menu_type' => 'page',
|
||||
'code' => 'system.agents',
|
||||
'name' => '代理管理',
|
||||
'path' => '/admin/agents',
|
||||
'route_name' => 'admin.agents',
|
||||
'component' => 'agents/index',
|
||||
'icon' => null,
|
||||
'active_menu_code' => null,
|
||||
'sort_order' => 25,
|
||||
'is_visible' => true,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ([
|
||||
['permission_code' => 'agent.node.view', 'action_id' => (int) $viewActionId, 'name' => '代理节点查看'],
|
||||
['permission_code' => 'agent.node.manage', 'action_id' => (int) $manageActionId, 'name' => '代理节点管理'],
|
||||
] as $row) {
|
||||
if (DB::table('admin_menu_actions')->where('permission_code', $row['permission_code'])->exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => (int) $agentMenuId,
|
||||
'action_id' => $row['action_id'],
|
||||
'permission_code' => $row['permission_code'],
|
||||
'name' => $row['name'],
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.agent-nodes.'),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
$permissionCodes = $resource['permission_codes'] ?? [];
|
||||
foreach ($permissionCodes as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('admin_role_api_resources')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
if ($superRoleId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
|
||||
$menuActionIdList = DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', ['agent.node.view', 'agent.node.manage'])
|
||||
->pluck('id');
|
||||
|
||||
foreach ($menuActionIdList as $menuActionId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = [
|
||||
'admin.agent-nodes.tree',
|
||||
'admin.agent-nodes.store',
|
||||
'admin.agent-nodes.show',
|
||||
'admin.agent-nodes.update',
|
||||
'admin.agent-nodes.children',
|
||||
];
|
||||
|
||||
foreach ($codes as $code) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $code)->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
DB::table('admin_role_api_resources')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
}
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', ['agent.node.view', 'agent.node.manage'])
|
||||
->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_roles', function (Blueprint $table): void {
|
||||
$table->foreignId('owner_agent_id')->nullable()->after('sort_order')->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->foreignId('delegated_from_role_id')->nullable()->after('owner_agent_id')->constrained('admin_roles')->nullOnDelete();
|
||||
$table->string('scope_type', 16)->default('system')->after('delegated_from_role_id');
|
||||
});
|
||||
|
||||
Schema::create('admin_user_agent_roles', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')->constrained('admin_users')->cascadeOnDelete();
|
||||
$table->foreignId('agent_node_id')->constrained('agent_nodes')->cascadeOnDelete();
|
||||
$table->foreignId('role_id')->constrained('admin_roles')->cascadeOnDelete();
|
||||
$table->timestamp('granted_at')->nullable();
|
||||
$table->primary(['admin_user_id', 'agent_node_id', 'role_id'], 'pk_admin_user_agent_roles');
|
||||
});
|
||||
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->foreignId('agent_node_id')->nullable()->after('site_code')->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->index(['site_code', 'agent_node_id'], 'idx_players_site_agent');
|
||||
});
|
||||
|
||||
DB::table('admin_roles')->update(['scope_type' => 'system']);
|
||||
|
||||
$this->backfillAdminUserAgentRoles();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_players_site_agent');
|
||||
$table->dropConstrainedForeignId('agent_node_id');
|
||||
});
|
||||
|
||||
Schema::dropIfExists('admin_user_agent_roles');
|
||||
|
||||
Schema::table('admin_roles', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('delegated_from_role_id');
|
||||
$table->dropConstrainedForeignId('owner_agent_id');
|
||||
$table->dropColumn('scope_type');
|
||||
});
|
||||
}
|
||||
|
||||
private function backfillAdminUserAgentRoles(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$rows = DB::table('admin_user_site_roles as usr')
|
||||
->join('admin_user_agents as uaa', 'uaa.admin_user_id', '=', 'usr.admin_user_id')
|
||||
->join('agent_nodes as an', static function ($join): void {
|
||||
$join->on('an.id', '=', 'uaa.agent_node_id')
|
||||
->on('an.admin_site_id', '=', 'usr.site_id');
|
||||
})
|
||||
->select(['usr.admin_user_id', 'uaa.agent_node_id', 'usr.role_id', 'usr.granted_at'])
|
||||
->get();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
DB::table('admin_user_agent_roles')->updateOrInsert(
|
||||
[
|
||||
'admin_user_id' => (int) $row->admin_user_id,
|
||||
'agent_node_id' => (int) $row->agent_node_id,
|
||||
'role_id' => (int) $row->role_id,
|
||||
],
|
||||
[
|
||||
'granted_at' => $row->granted_at ?? $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 代理角色/账号 API 绑定到已有 agent.node.view / agent.node.manage 动作(同菜单下 action 唯一)。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.agent-roles.')
|
||||
|| str_starts_with((string) $resource['code'], 'admin.agent-admin-users.'),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] ?? [] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('admin_role_api_resources')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
if ($superRoleId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_role_api_resources')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = [
|
||||
'admin.agent-roles.update',
|
||||
'admin.agent-roles.destroy',
|
||||
'admin.agent-roles.permissions.sync',
|
||||
'admin.agent-roles.index',
|
||||
'admin.agent-roles.store',
|
||||
'admin.agent-admin-users.index',
|
||||
'admin.agent-admin-users.store',
|
||||
'admin.agent-admin-users.roles.sync',
|
||||
];
|
||||
|
||||
foreach ($codes as $code) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $code)->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Schema::hasTable('admin_role_api_resources')) {
|
||||
DB::table('admin_role_api_resources')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
}
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('agent_delegation_grants', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('parent_agent_id')->constrained('agent_nodes')->cascadeOnDelete();
|
||||
$table->foreignId('child_agent_id')->constrained('agent_nodes')->cascadeOnDelete();
|
||||
$table->foreignId('menu_action_id')->constrained('admin_menu_actions')->cascadeOnDelete();
|
||||
$table->boolean('can_delegate')->default(false);
|
||||
$table->foreignId('granted_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->timestamp('granted_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['child_agent_id', 'menu_action_id'], 'uk_agent_delegation_child_action');
|
||||
$table->index(['parent_agent_id', 'child_agent_id'], 'idx_agent_delegation_parent_child');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('agent_delegation_grants');
|
||||
}
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 将未归属玩家挂到对应主站根代理(与 agent_nodes depth=0 1:1)。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! \Illuminate\Support\Facades\Schema::hasColumn('players', 'agent_node_id')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roots = DB::table('agent_nodes as an')
|
||||
->join('admin_sites as s', 's.id', '=', 'an.admin_site_id')
|
||||
->where('an.depth', 0)
|
||||
->get(['an.id as root_id', 's.code as site_code']);
|
||||
|
||||
foreach ($roots as $root) {
|
||||
DB::table('players')
|
||||
->where('site_code', (string) $root->site_code)
|
||||
->whereNull('agent_node_id')
|
||||
->update(['agent_node_id' => (int) $root->root_id]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚归属,避免误清空业务绑定。
|
||||
}
|
||||
};
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 代理「节点 / 角色 / 账号」查看与管理拆分为独立 permission_code,避免只勾一项却获得全部管理能力。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$viewActionId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
$manageActionId = DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
if ($viewActionId === null || $manageActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$agentMenuId = (int) DB::table('admin_menus')->where('code', 'system.agents')->value('id');
|
||||
if ($agentMenuId === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rolesMenuId = $this->ensureChildMenu($agentMenuId, 'system.agents.roles', '代理角色', $now);
|
||||
$usersMenuId = $this->ensureChildMenu($agentMenuId, 'system.agents.users', '代理账号', $now);
|
||||
|
||||
$this->ensureMenuAction((int) $rolesMenuId, (int) $viewActionId, 'agent.role.view', '代理角色查看', $now);
|
||||
$this->ensureMenuAction((int) $rolesMenuId, (int) $manageActionId, 'agent.role.manage', '代理角色管理', $now);
|
||||
$this->ensureMenuAction((int) $usersMenuId, (int) $viewActionId, 'agent.user.view', '代理账号查看', $now);
|
||||
$this->ensureMenuAction((int) $usersMenuId, (int) $manageActionId, 'agent.user.manage', '代理账号管理', $now);
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$nodeViewId = $menuActionIds['agent.node.view'] ?? null;
|
||||
$nodeManageId = $menuActionIds['agent.node.manage'] ?? null;
|
||||
$roleViewId = $menuActionIds['agent.role.view'] ?? null;
|
||||
$roleManageId = $menuActionIds['agent.role.manage'] ?? null;
|
||||
$userViewId = $menuActionIds['agent.user.view'] ?? null;
|
||||
$userManageId = $menuActionIds['agent.user.manage'] ?? null;
|
||||
|
||||
if ($nodeViewId !== null && $roleViewId !== null && $userViewId !== null) {
|
||||
$roleIdsWithNodeView = DB::table('admin_role_menu_actions')
|
||||
->where('menu_action_id', (int) $nodeViewId)
|
||||
->pluck('role_id')
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
foreach ($roleIdsWithNodeView as $roleId) {
|
||||
foreach ([$roleViewId, $userViewId] as $actionId) {
|
||||
$this->attachRoleMenuAction((int) $roleId, (int) $actionId, $now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($nodeManageId !== null && $roleManageId !== null && $userManageId !== null) {
|
||||
$roleIdsWithNodeManage = DB::table('admin_role_menu_actions')
|
||||
->where('menu_action_id', (int) $nodeManageId)
|
||||
->pluck('role_id')
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
foreach ($roleIdsWithNodeManage as $roleId) {
|
||||
foreach ([$roleManageId, $userManageId] as $actionId) {
|
||||
$this->attachRoleMenuAction((int) $roleId, (int) $actionId, $now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.agent-')
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] ?? [] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureChildMenu(int $parentId, string $code, string $name, Carbon $now): int
|
||||
{
|
||||
$existing = DB::table('admin_menus')->where('code', $code)->value('id');
|
||||
if ($existing !== null) {
|
||||
return (int) $existing;
|
||||
}
|
||||
|
||||
return (int) DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => $parentId,
|
||||
'menu_type' => 'button',
|
||||
'code' => $code,
|
||||
'name' => $name,
|
||||
'path' => null,
|
||||
'route_name' => null,
|
||||
'component' => null,
|
||||
'icon' => null,
|
||||
'active_menu_code' => 'system.agents',
|
||||
'sort_order' => 0,
|
||||
'is_visible' => false,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
private function ensureMenuAction(int $menuId, int $actionId, string $permissionCode, string $name, Carbon $now): void
|
||||
{
|
||||
if (DB::table('admin_menu_actions')->where('permission_code', $permissionCode)->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => $menuId,
|
||||
'action_id' => $actionId,
|
||||
'permission_code' => $permissionCode,
|
||||
'name' => $name,
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
private function attachRoleMenuAction(int $roleId, int $menuActionId, Carbon $now): void
|
||||
{
|
||||
$exists = DB::table('admin_role_menu_actions')
|
||||
->where('role_id', $roleId)
|
||||
->where('menu_action_id', $menuActionId)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_role_menu_actions')->insert([
|
||||
'role_id' => $roleId,
|
||||
'menu_action_id' => $menuActionId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = ['agent.role.view', 'agent.role.manage', 'agent.user.view', 'agent.user.manage'];
|
||||
$actionIds = DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->pluck('id')->all();
|
||||
|
||||
if ($actionIds !== []) {
|
||||
DB::table('admin_role_menu_actions')->whereIn('menu_action_id', $actionIds)->delete();
|
||||
DB::table('admin_api_resource_bindings')->whereIn('menu_action_id', $actionIds)->delete();
|
||||
DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->delete();
|
||||
}
|
||||
|
||||
DB::table('admin_menus')->whereIn('code', ['system.agents.roles', 'system.agents.users'])->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/** 补齐代理账号删除 API 资源(admin.agent-admin-users.destroy)。 */
|
||||
return new class extends Migration
|
||||
{
|
||||
private const RESOURCE_CODE = 'admin.agent-admin-users.destroy';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$resource = collect(AdminAuthorizationRegistry::resources())
|
||||
->firstWhere('code', self::RESOURCE_CODE);
|
||||
|
||||
if ($resource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', self::RESOURCE_CODE)
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => self::RESOURCE_CODE,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', self::RESOURCE_CODE)
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$sites = DB::table('admin_sites')->orderBy('id')->get(['id', 'code']);
|
||||
|
||||
foreach ($sites as $site) {
|
||||
$siteId = (int) $site->id;
|
||||
$code = (string) $site->code;
|
||||
$legacyCode = 'root-'.$code;
|
||||
|
||||
$root = DB::table('agent_nodes')
|
||||
->where('admin_site_id', $siteId)
|
||||
->where('depth', 0)
|
||||
->first(['id', 'code']);
|
||||
|
||||
if ($root === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((string) $root->code === $legacyCode) {
|
||||
$conflict = DB::table('agent_nodes')
|
||||
->where('admin_site_id', $siteId)
|
||||
->where('code', $code)
|
||||
->where('id', '!=', (int) $root->id)
|
||||
->exists();
|
||||
if (! $conflict) {
|
||||
DB::table('agent_nodes')->where('id', (int) $root->id)->update([
|
||||
'code' => $code,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$sites = DB::table('admin_sites')->orderBy('id')->get(['id', 'code']);
|
||||
|
||||
foreach ($sites as $site) {
|
||||
$siteId = (int) $site->id;
|
||||
$code = (string) $site->code;
|
||||
|
||||
DB::table('agent_nodes')
|
||||
->where('admin_site_id', $siteId)
|
||||
->where('depth', 0)
|
||||
->where('code', $code)
|
||||
->update([
|
||||
'code' => 'root-'.$code,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('agent_profiles', function (Blueprint $table): void {
|
||||
$table->foreignId('agent_node_id')->primary()->constrained('agent_nodes')->cascadeOnDelete();
|
||||
$table->decimal('total_share_rate', 5, 2)->default(0)->comment('总占成 0-100');
|
||||
$table->unsignedBigInteger('credit_limit')->default(0);
|
||||
$table->unsignedBigInteger('allocated_credit')->default(0);
|
||||
$table->unsignedBigInteger('used_credit')->default(0);
|
||||
$table->decimal('rebate_limit', 8, 4)->default(0);
|
||||
$table->decimal('default_player_rebate', 8, 4)->default(0);
|
||||
$table->string('settlement_cycle', 16)->default('weekly');
|
||||
$table->boolean('can_grant_extra_rebate')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('player_credit_accounts', function (Blueprint $table): void {
|
||||
$table->foreignId('player_id')->primary()->constrained('players')->cascadeOnDelete();
|
||||
$table->unsignedBigInteger('credit_limit')->default(0);
|
||||
$table->unsignedBigInteger('used_credit')->default(0);
|
||||
$table->unsignedBigInteger('frozen_credit')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('player_rebate_profiles', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->string('game_type', 32)->default('*');
|
||||
$table->boolean('inherit_from_agent')->default(true);
|
||||
$table->decimal('rebate_rate', 8, 4)->default(0);
|
||||
$table->decimal('extra_rebate_rate', 8, 4)->default(0);
|
||||
$table->timestamps();
|
||||
$table->unique(['player_id', 'game_type']);
|
||||
});
|
||||
|
||||
Schema::create('settlement_periods', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('admin_site_id')->constrained('admin_sites')->cascadeOnDelete();
|
||||
$table->timestamp('period_start');
|
||||
$table->timestamp('period_end');
|
||||
$table->string('status', 16)->default('open');
|
||||
$table->timestamps();
|
||||
$table->index(['admin_site_id', 'status']);
|
||||
});
|
||||
|
||||
Schema::create('settlement_bills', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('settlement_period_id')->constrained('settlement_periods')->cascadeOnDelete();
|
||||
$table->string('bill_type', 16);
|
||||
$table->string('owner_type', 16);
|
||||
$table->unsignedBigInteger('owner_id');
|
||||
$table->string('counterparty_type', 16);
|
||||
$table->unsignedBigInteger('counterparty_id');
|
||||
$table->bigInteger('gross_win_loss')->default(0);
|
||||
$table->bigInteger('rebate_amount')->default(0);
|
||||
$table->bigInteger('adjustment_amount')->default(0);
|
||||
$table->bigInteger('net_amount')->default(0);
|
||||
$table->bigInteger('paid_amount')->default(0);
|
||||
$table->bigInteger('unpaid_amount')->default(0);
|
||||
$table->string('status', 16)->default('pending');
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
$table->timestamps();
|
||||
$table->index(['settlement_period_id', 'bill_type']);
|
||||
});
|
||||
|
||||
Schema::create('rebate_records', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('settlement_period_id')->nullable()->constrained('settlement_periods')->nullOnDelete();
|
||||
$table->string('game_type', 32)->default('*');
|
||||
$table->unsignedBigInteger('valid_bet_amount')->default(0);
|
||||
$table->decimal('rebate_rate', 8, 4)->default(0);
|
||||
$table->unsignedBigInteger('rebate_amount')->default(0);
|
||||
$table->string('rebate_type', 16)->default('basic');
|
||||
$table->foreignId('owner_agent_id')->nullable()->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->string('status', 16)->default('pending');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('rebate_allocations', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('rebate_record_id')->constrained('rebate_records')->cascadeOnDelete();
|
||||
$table->foreignId('settlement_bill_id')->nullable()->constrained('settlement_bills')->nullOnDelete();
|
||||
$table->string('participant_type', 16);
|
||||
$table->unsignedBigInteger('participant_id')->default(0);
|
||||
$table->decimal('actual_share_rate', 5, 2)->default(0);
|
||||
$table->bigInteger('allocated_amount')->default(0);
|
||||
$table->string('allocation_rule', 32)->default('share');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('payment_records', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('settlement_bill_id')->constrained('settlement_bills')->cascadeOnDelete();
|
||||
$table->string('payer_type', 16);
|
||||
$table->unsignedBigInteger('payer_id');
|
||||
$table->string('payee_type', 16);
|
||||
$table->unsignedBigInteger('payee_id');
|
||||
$table->bigInteger('amount');
|
||||
$table->string('method', 32)->nullable();
|
||||
$table->string('status', 16)->default('pending');
|
||||
$table->foreignId('created_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->foreignId('confirmed_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('credit_ledger', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('owner_type', 16);
|
||||
$table->unsignedBigInteger('owner_id');
|
||||
$table->bigInteger('amount');
|
||||
$table->string('reason', 64);
|
||||
$table->string('ref_type', 32)->nullable();
|
||||
$table->unsignedBigInteger('ref_id')->nullable();
|
||||
$table->timestamps();
|
||||
$table->index(['owner_type', 'owner_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('credit_ledger');
|
||||
Schema::dropIfExists('payment_records');
|
||||
Schema::dropIfExists('rebate_allocations');
|
||||
Schema::dropIfExists('rebate_records');
|
||||
Schema::dropIfExists('settlement_bills');
|
||||
Schema::dropIfExists('settlement_periods');
|
||||
Schema::dropIfExists('player_rebate_profiles');
|
||||
Schema::dropIfExists('player_credit_accounts');
|
||||
Schema::dropIfExists('agent_profiles');
|
||||
}
|
||||
};
|
||||
@@ -1,155 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAgentLineSettlementPermissionMenuActionSync;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 代理账单 / 线路开通等 API 写入 admin_api_resources,并补齐 settlement.agent.* menu_action。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const RESOURCE_CODE_PREFIXES = [
|
||||
'admin.settlement-bills.',
|
||||
'admin.settlement-periods.',
|
||||
'admin.settlement-payments.',
|
||||
'admin.settlement-adjustments.',
|
||||
'admin.settlement-reports.',
|
||||
'admin.credit-ledger.',
|
||||
'admin.agent-lines.',
|
||||
'admin.agent-nodes.profile.',
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
private const MENU_ACTION_CODES = [
|
||||
'settlement.agent.view',
|
||||
'settlement.agent.manage',
|
||||
'agent.line.provision',
|
||||
'agent.profile.manage',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
AdminAgentLineSettlementPermissionMenuActionSync::syncMissing();
|
||||
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => self::matchesResourceCode((string) $resource['code']),
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->grantSuperAdminMenuActions();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (AdminAuthorizationRegistry::resources() as $resource) {
|
||||
if (! self::matchesResourceCode((string) $resource['code'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static function matchesResourceCode(string $code): bool
|
||||
{
|
||||
foreach (self::RESOURCE_CODE_PREFIXES as $prefix) {
|
||||
if (str_starts_with($code, $prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function grantSuperAdminMenuActions(): void
|
||||
{
|
||||
$superRoleId = DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
if ($superRoleId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')
|
||||
->whereIn('permission_code', self::MENU_ACTION_CODES)
|
||||
->pluck('id');
|
||||
|
||||
foreach ($menuActionIds as $menuActionId) {
|
||||
DB::table('admin_role_menu_actions')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
]);
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('admin_role_legacy_permissions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (['prd.settlement.agent.view', 'prd.settlement.agent.manage', 'prd.agent-line.provision', 'prd.agent.profile.manage'] as $slug) {
|
||||
DB::table('admin_role_legacy_permissions')->updateOrInsert([
|
||||
'role_id' => (int) $superRoleId,
|
||||
'permission_slug' => $slug,
|
||||
], []);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('agent_profiles', function (Blueprint $table): void {
|
||||
$table->boolean('can_create_child_agent')->default(false)->after('can_grant_extra_rebate');
|
||||
$table->boolean('can_create_player')->default(true)->after('can_create_child_agent');
|
||||
});
|
||||
|
||||
\Illuminate\Support\Facades\DB::table('agent_profiles')->update([
|
||||
'can_create_child_agent' => true,
|
||||
'can_create_player' => true,
|
||||
]);
|
||||
|
||||
\App\Support\AgentDefaultRolePermissions::ensurePlatformAgentRole();
|
||||
\App\Models\AdminUser::query()
|
||||
->whereIn('id', \Illuminate\Support\Facades\DB::table('admin_user_agents')->pluck('admin_user_id'))
|
||||
->each(static function (\App\Models\AdminUser $user): void {
|
||||
$agentNodeId = $user->primaryAgentNodeId();
|
||||
if ($agentNodeId !== null) {
|
||||
$user->syncPrimaryPlatformAgentRole($agentNodeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('agent_profiles', function (Blueprint $table): void {
|
||||
$table->dropColumn(['can_create_child_agent', 'can_create_player']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 修正代理主账号 admin_users.status 与 agent_nodes.status 语义不一致的历史数据。
|
||||
*
|
||||
* admin_users: 0=可登录, 1=禁用
|
||||
* agent_nodes: 1=启用, 0=停用
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = now();
|
||||
|
||||
$enabledUserIds = DB::table('admin_user_agents as aua')
|
||||
->join('agent_nodes as an', 'an.id', '=', 'aua.agent_node_id')
|
||||
->join('admin_users as au', 'au.id', '=', 'aua.admin_user_id')
|
||||
->where('aua.is_primary', true)
|
||||
->where('an.status', 1)
|
||||
->where('au.status', 1)
|
||||
->pluck('au.id');
|
||||
|
||||
if ($enabledUserIds->isNotEmpty()) {
|
||||
DB::table('admin_users')
|
||||
->whereIn('id', $enabledUserIds->all())
|
||||
->update(['status' => 0, 'updated_at' => $now]);
|
||||
}
|
||||
|
||||
$disabledUserIds = DB::table('admin_user_agents as aua')
|
||||
->join('agent_nodes as an', 'an.id', '=', 'aua.agent_node_id')
|
||||
->join('admin_users as au', 'au.id', '=', 'aua.admin_user_id')
|
||||
->where('aua.is_primary', true)
|
||||
->where('an.status', 0)
|
||||
->where('au.status', 0)
|
||||
->pluck('au.id');
|
||||
|
||||
if ($disabledUserIds->isNotEmpty()) {
|
||||
DB::table('admin_users')
|
||||
->whereIn('id', $disabledUserIds->all())
|
||||
->update(['status' => 1, 'updated_at' => $now]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不可逆:无法可靠还原误写前的 admin_users.status
|
||||
}
|
||||
};
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ticket_items', function (Blueprint $table): void {
|
||||
$table->foreignId('agent_node_id')->nullable()->after('player_id')->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->json('share_snapshot')->nullable()->after('rule_snapshot_json');
|
||||
$table->decimal('agent_rebate_rate_snapshot', 8, 4)->nullable()->after('share_snapshot');
|
||||
$table->timestamp('agent_settled_at')->nullable()->after('settled_at');
|
||||
$table->foreignId('agent_settlement_reversal_of_id')->nullable()->after('agent_settled_at')
|
||||
->constrained('ticket_items')->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('share_ledger', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('ticket_item_id')->constrained('ticket_items')->cascadeOnDelete();
|
||||
$table->foreignId('player_id')->constrained('players')->cascadeOnDelete();
|
||||
$table->foreignId('agent_node_id')->nullable()->constrained('agent_nodes')->nullOnDelete();
|
||||
$table->json('agent_path')->nullable();
|
||||
$table->json('share_snapshot')->nullable();
|
||||
$table->bigInteger('game_win_loss')->default(0);
|
||||
$table->bigInteger('basic_rebate')->default(0);
|
||||
$table->bigInteger('shared_net_win_loss')->default(0);
|
||||
$table->json('allocations_json')->nullable();
|
||||
$table->foreignId('settlement_period_id')->nullable()->constrained('settlement_periods')->nullOnDelete();
|
||||
$table->unsignedBigInteger('reversal_of_id')->nullable();
|
||||
$table->timestamp('settled_at');
|
||||
$table->timestamps();
|
||||
$table->index(['settled_at', 'player_id']);
|
||||
$table->index(['settlement_period_id']);
|
||||
});
|
||||
|
||||
Schema::table('share_ledger', function (Blueprint $table): void {
|
||||
$table->foreign('reversal_of_id')->references('id')->on('share_ledger')->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::table('rebate_records', function (Blueprint $table): void {
|
||||
$table->foreignId('ticket_item_id')->nullable()->after('player_id')->constrained('ticket_items')->nullOnDelete();
|
||||
$table->foreignId('reversal_of_id')->nullable()->after('ticket_item_id')->constrained('rebate_records')->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::table('settlement_bills', function (Blueprint $table): void {
|
||||
$table->timestamp('locked_at')->nullable()->after('confirmed_at');
|
||||
$table->foreignId('reversed_bill_id')->nullable()->after('locked_at')->constrained('settlement_bills')->nullOnDelete();
|
||||
$table->json('meta_json')->nullable()->after('reversed_bill_id');
|
||||
});
|
||||
|
||||
Schema::create('settlement_adjustments', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('settlement_period_id')->nullable()->constrained('settlement_periods')->nullOnDelete();
|
||||
$table->foreignId('original_bill_id')->nullable()->constrained('settlement_bills')->nullOnDelete();
|
||||
$table->string('adjustment_type', 32);
|
||||
$table->bigInteger('amount');
|
||||
$table->string('reason', 255)->nullable();
|
||||
$table->foreignId('created_by')->nullable()->constrained('admin_users')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('settlement_adjustments');
|
||||
|
||||
Schema::table('settlement_bills', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('reversed_bill_id');
|
||||
$table->dropColumn(['locked_at', 'meta_json']);
|
||||
});
|
||||
|
||||
Schema::table('rebate_records', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('reversal_of_id');
|
||||
$table->dropConstrainedForeignId('ticket_item_id');
|
||||
});
|
||||
|
||||
Schema::dropIfExists('share_ledger');
|
||||
|
||||
Schema::table('ticket_items', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('agent_settlement_reversal_of_id');
|
||||
$table->dropConstrainedForeignId('agent_node_id');
|
||||
$table->dropColumn(['share_snapshot', 'agent_rebate_rate_snapshot', 'agent_settled_at']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->string('auth_source', 16)->default('main_site_sso')->after('site_player_id');
|
||||
$table->string('funding_mode', 16)->default('wallet')->after('auth_source');
|
||||
$table->string('password_hash', 255)->nullable()->after('username');
|
||||
$table->unsignedSmallInteger('login_failed_count')->default(0)->after('last_login_at');
|
||||
$table->timestamp('login_locked_until')->nullable()->after('login_failed_count');
|
||||
});
|
||||
|
||||
DB::table('players')->update([
|
||||
'auth_source' => 'main_site_sso',
|
||||
'funding_mode' => 'wallet',
|
||||
]);
|
||||
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->index(['site_code', 'auth_source', 'username'], 'idx_players_site_auth_username');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->dropIndex('idx_players_site_auth_username');
|
||||
$table->dropColumn([
|
||||
'auth_source',
|
||||
'funding_mode',
|
||||
'password_hash',
|
||||
'login_failed_count',
|
||||
'login_locked_until',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('payment_records', function (Blueprint $table): void {
|
||||
$table->text('proof')->nullable()->after('method');
|
||||
$table->string('remark', 255)->nullable()->after('proof');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('payment_records', function (Blueprint $table): void {
|
||||
$table->dropColumn(['proof', 'remark']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\AdminRole;
|
||||
use App\Models\AgentNode;
|
||||
use App\Support\AgentDefaultRolePermissions;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
AgentNode::query()->each(static function (AgentNode $node): void {
|
||||
$role = AdminRole::query()
|
||||
->where('owner_agent_id', $node->id)
|
||||
->where('slug', 'agent_owner_'.$node->id)
|
||||
->first();
|
||||
|
||||
if ($role === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$role->syncLegacyPermissionSlugs(AgentDefaultRolePermissions::ownerSlugsForNode($node));
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 权限包为产品策略,回滚不恢复旧 slug 集合。
|
||||
}
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\AdminRole;
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\AgentNode;
|
||||
use App\Support\AgentDefaultRolePermissions;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$platformRole = AgentDefaultRolePermissions::ensurePlatformAgentRole();
|
||||
|
||||
AgentNode::query()->each(static function (AgentNode $node): void {
|
||||
$ownerRole = AdminRole::query()
|
||||
->where('owner_agent_id', $node->id)
|
||||
->where('slug', 'agent_owner_'.$node->id)
|
||||
->first();
|
||||
|
||||
if ($ownerRole !== null) {
|
||||
$ownerRole->syncLegacyPermissionSlugs(AgentDefaultRolePermissions::ownerSlugsForNode($node));
|
||||
}
|
||||
});
|
||||
|
||||
$bindings = DB::table('admin_user_agents')->get(['admin_user_id', 'agent_node_id']);
|
||||
foreach ($bindings as $binding) {
|
||||
$adminUserId = (int) $binding->admin_user_id;
|
||||
$agentNodeId = (int) $binding->agent_node_id;
|
||||
$user = AdminUser::query()->find($adminUserId);
|
||||
if ($user === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$agentRoleIds = DB::table('admin_user_agent_roles')
|
||||
->where('admin_user_id', $adminUserId)
|
||||
->where('agent_node_id', $agentNodeId)
|
||||
->pluck('role_id')
|
||||
->map(static fn ($id): int => (int) $id)
|
||||
->all();
|
||||
|
||||
if ($agentRoleIds === []) {
|
||||
$ownerId = (int) (AdminRole::query()
|
||||
->where('owner_agent_id', $agentNodeId)
|
||||
->where('slug', 'agent_owner_'.$agentNodeId)
|
||||
->value('id') ?? 0);
|
||||
if ($ownerId > 0) {
|
||||
$agentRoleIds = [$ownerId];
|
||||
}
|
||||
}
|
||||
|
||||
if ($agentRoleIds !== []) {
|
||||
$user->syncAgentRoleIds($agentNodeId, $agentRoleIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚权限与 pivot,避免经营账号失权。
|
||||
}
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('settlement_bills', function (Blueprint $table): void {
|
||||
$table->bigInteger('platform_rounding_adjustment')->default(0)->after('adjustment_amount');
|
||||
});
|
||||
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->json('risk_tags')->nullable()->after('status');
|
||||
});
|
||||
|
||||
Schema::table('agent_nodes', function (Blueprint $table): void {
|
||||
$table->json('risk_tags')->nullable()->after('status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('agent_nodes', function (Blueprint $table): void {
|
||||
$table->dropColumn('risk_tags');
|
||||
});
|
||||
|
||||
Schema::table('players', function (Blueprint $table): void {
|
||||
$table->dropColumn('risk_tags');
|
||||
});
|
||||
|
||||
Schema::table('settlement_bills', function (Blueprint $table): void {
|
||||
$table->dropColumn('platform_rounding_adjustment');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\AdminRole;
|
||||
use App\Models\AdminUser;
|
||||
use App\Support\AgentDefaultRolePermissions;
|
||||
use App\Support\AgentPlatformRole;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
AgentDefaultRolePermissions::ensurePlatformAgentRole();
|
||||
$platformRoleId = AgentPlatformRole::id();
|
||||
|
||||
foreach (DB::table('admin_user_agents')->get(['admin_user_id', 'agent_node_id']) as $binding) {
|
||||
$user = AdminUser::query()->find((int) $binding->admin_user_id);
|
||||
if ($user === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$user->syncPrimaryPlatformAgentRole((int) $binding->agent_node_id);
|
||||
}
|
||||
|
||||
$ownerRoleIds = AdminRole::query()
|
||||
->where('scope_type', AdminRole::SCOPE_AGENT)
|
||||
->where('slug', 'like', 'agent_owner_%')
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
if ($ownerRoleIds !== []) {
|
||||
DB::table('admin_user_agent_roles')->whereIn('role_id', $ownerRoleIds)->delete();
|
||||
DB::table('admin_user_site_roles')->whereIn('role_id', $ownerRoleIds)->delete();
|
||||
DB::table('admin_role_menu_actions')->whereIn('role_id', $ownerRoleIds)->delete();
|
||||
AdminRole::query()->whereIn('id', $ownerRoleIds)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚:避免经营账号失权。
|
||||
}
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Support\PlatformSystemRoles;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
PlatformSystemRoles::ensureAll();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚内置角色与权限,避免平台/代理账号失权。
|
||||
}
|
||||
};
|
||||
@@ -1,94 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
|
||||
/**
|
||||
* 信用流水 API 注册到 admin_api_resources(已有库增量同步,避免 500 api_resource_not_configured)。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const RESOURCE_CODES = [
|
||||
'admin.credit-ledger.index',
|
||||
'admin.settlement-payments.index',
|
||||
'admin.settlement-adjustments.index',
|
||||
'admin.settlement-reports.summary',
|
||||
'admin.settlement-reports.show',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$byCode = collect(AdminAuthorizationRegistry::resources())->keyBy('code');
|
||||
|
||||
foreach (self::RESOURCE_CODES as $code) {
|
||||
$resource = $byCode->get($code);
|
||||
if (! is_array($resource)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', $resource['code'])
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => $resource['code'],
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (self::RESOURCE_CODES as $code) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $code)->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->where('api_resource_id', (int) $resourceId)->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
}
|
||||
};
|
||||
18
database/migrations/README.md
Normal file
18
database/migrations/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 迁移目录说明
|
||||
|
||||
当前项目已切换为 **schema dump 作为数据库基线** 的维护方式。
|
||||
|
||||
- 最终版 PostgreSQL 结构:[`../schema/pgsql-schema.sql`](../schema/pgsql-schema.sql)
|
||||
- 新环境初始化:优先加载 schema dump,再执行后续新增 migration
|
||||
- 旧的历史 migration 已清理,不再作为基线结构来源
|
||||
|
||||
后续规则:
|
||||
|
||||
1. 新增数据库结构变更时,继续正常创建新的 migration 文件放在本目录。
|
||||
2. 当结构进入一个新的稳定阶段后,可重新执行:
|
||||
|
||||
```bash
|
||||
php artisan schema:dump --database=pgsql --prune
|
||||
```
|
||||
|
||||
3. 执行 `--prune` 前,确认团队已接受“历史迁移链不再保留”的方式。
|
||||
4889
database/schema/pgsql-schema.sql
Normal file
4889
database/schema/pgsql-schema.sql
Normal file
@@ -0,0 +1,4889 @@
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
\restrict rPXEgF1VaYgsz0ptn4X1KcYROWRPYlYb6daN4zAOY961hMNjxCs5gLhsUZO9N0E
|
||||
|
||||
-- Dumped from database version 18.3(ServBay)
|
||||
-- Dumped by pg_dump version 18.3(ServBay)
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET transaction_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_action_catalog (
|
||||
id bigint NOT NULL,
|
||||
code character varying(64) NOT NULL,
|
||||
name character varying(64) NOT NULL,
|
||||
sort_order integer DEFAULT 0 NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_action_catalog.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_action_catalog.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_action_catalog_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_action_catalog_id_seq OWNED BY public.admin_action_catalog.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_api_resource_bindings (
|
||||
id bigint NOT NULL,
|
||||
api_resource_id bigint NOT NULL,
|
||||
menu_action_id bigint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_api_resource_bindings_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_api_resource_bindings_id_seq OWNED BY public.admin_api_resource_bindings.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_api_resources (
|
||||
id bigint NOT NULL,
|
||||
code character varying(128) NOT NULL,
|
||||
module_code character varying(64) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
http_method character varying(16) NOT NULL,
|
||||
uri_pattern character varying(255) NOT NULL,
|
||||
route_name character varying(255),
|
||||
auth_mode character varying(24) DEFAULT 'permission_required'::character varying NOT NULL,
|
||||
is_audit_required boolean DEFAULT false NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
meta_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_api_resources.auth_mode; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_api_resources.auth_mode IS 'login_only|permission_required|internal_only';
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_api_resources.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_api_resources.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_api_resources_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_api_resources_id_seq OWNED BY public.admin_api_resources.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_menu_actions (
|
||||
id bigint NOT NULL,
|
||||
menu_id bigint NOT NULL,
|
||||
action_id bigint NOT NULL,
|
||||
permission_code character varying(128) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_menu_actions.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_menu_actions.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_menu_actions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_menu_actions_id_seq OWNED BY public.admin_menu_actions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_menus (
|
||||
id bigint NOT NULL,
|
||||
parent_id bigint,
|
||||
menu_type character varying(24) NOT NULL,
|
||||
code character varying(128) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
path character varying(255),
|
||||
route_name character varying(255),
|
||||
component character varying(255),
|
||||
icon character varying(128),
|
||||
active_menu_code character varying(128),
|
||||
sort_order integer DEFAULT 0 NOT NULL,
|
||||
is_visible boolean DEFAULT true NOT NULL,
|
||||
is_cache boolean DEFAULT false NOT NULL,
|
||||
is_external boolean DEFAULT false NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
meta_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_menus.menu_type; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_menus.menu_type IS 'directory|menu|page';
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_menus.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_menus.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_menus_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_menus_id_seq OWNED BY public.admin_menus.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_role_menu_actions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_role_menu_actions (
|
||||
role_id bigint NOT NULL,
|
||||
menu_action_id bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_roles (
|
||||
id bigint NOT NULL,
|
||||
slug character varying(64) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
code character varying(64) NOT NULL,
|
||||
description text,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
is_system boolean DEFAULT false NOT NULL,
|
||||
sort_order integer DEFAULT 0 NOT NULL,
|
||||
owner_agent_id bigint,
|
||||
delegated_from_role_id bigint,
|
||||
scope_type character varying(16) DEFAULT 'system'::character varying NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_roles.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_roles.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_roles_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_roles_id_seq OWNED BY public.admin_roles.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_sites (
|
||||
id bigint NOT NULL,
|
||||
code character varying(64) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
currency_code character varying(16) DEFAULT 'NPR'::character varying NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
is_default boolean DEFAULT false NOT NULL,
|
||||
extra_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
wallet_api_url character varying(512),
|
||||
wallet_debit_path character varying(128) DEFAULT '/wallet/debit-for-lottery'::character varying NOT NULL,
|
||||
wallet_credit_path character varying(128) DEFAULT '/wallet/credit-from-lottery'::character varying NOT NULL,
|
||||
wallet_balance_path character varying(128) DEFAULT '/wallet/balance'::character varying NOT NULL,
|
||||
wallet_api_key_encrypted text,
|
||||
sso_jwt_secret_encrypted text,
|
||||
wallet_timeout_seconds smallint DEFAULT '10'::smallint NOT NULL,
|
||||
iframe_allowed_origins json,
|
||||
lottery_h5_base_url character varying(512),
|
||||
notes text
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_sites.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_sites.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_sites_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_sites_id_seq OWNED BY public.admin_sites.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agent_roles; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_user_agent_roles (
|
||||
admin_user_id bigint NOT NULL,
|
||||
agent_node_id bigint NOT NULL,
|
||||
role_id bigint NOT NULL,
|
||||
granted_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agents; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_user_agents (
|
||||
admin_user_id bigint NOT NULL,
|
||||
agent_node_id bigint NOT NULL,
|
||||
is_primary boolean DEFAULT true NOT NULL,
|
||||
granted_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_menu_actions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_user_menu_actions (
|
||||
admin_user_id bigint NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
menu_action_id bigint NOT NULL,
|
||||
granted_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_site_roles; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_user_site_roles (
|
||||
admin_user_id bigint NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
role_id bigint NOT NULL,
|
||||
granted_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.admin_users (
|
||||
id bigint NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
email character varying(255),
|
||||
email_verified_at timestamp(0) without time zone,
|
||||
password character varying(255) NOT NULL,
|
||||
status smallint DEFAULT '0'::smallint NOT NULL,
|
||||
last_login_at timestamp(0) without time zone,
|
||||
remember_token character varying(100),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
username character varying(64) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN admin_users.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.admin_users.status IS '0=active,1=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.admin_users_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.admin_users_id_seq OWNED BY public.admin_users.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.agent_delegation_grants (
|
||||
id bigint NOT NULL,
|
||||
parent_agent_id bigint NOT NULL,
|
||||
child_agent_id bigint NOT NULL,
|
||||
menu_action_id bigint NOT NULL,
|
||||
can_delegate boolean DEFAULT false NOT NULL,
|
||||
granted_by bigint,
|
||||
granted_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.agent_delegation_grants_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.agent_delegation_grants_id_seq OWNED BY public.agent_delegation_grants.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.agent_nodes (
|
||||
id bigint NOT NULL,
|
||||
admin_site_id bigint NOT NULL,
|
||||
parent_id bigint,
|
||||
path character varying(512) NOT NULL,
|
||||
depth smallint DEFAULT '0'::smallint NOT NULL,
|
||||
code character varying(64) NOT NULL,
|
||||
name character varying(128) NOT NULL,
|
||||
status smallint DEFAULT '1'::smallint NOT NULL,
|
||||
created_by bigint,
|
||||
extra_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
risk_tags json
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN agent_nodes.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.agent_nodes.status IS '1=enabled,0=disabled';
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.agent_nodes_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.agent_nodes_id_seq OWNED BY public.agent_nodes.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_profiles; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.agent_profiles (
|
||||
agent_node_id bigint NOT NULL,
|
||||
total_share_rate numeric(5,2) DEFAULT '0'::numeric NOT NULL,
|
||||
credit_limit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
allocated_credit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
used_credit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_limit numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
default_player_rebate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
settlement_cycle character varying(16) DEFAULT 'weekly'::character varying NOT NULL,
|
||||
can_grant_extra_rebate boolean DEFAULT false NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
can_create_child_agent boolean DEFAULT false NOT NULL,
|
||||
can_create_player boolean DEFAULT true NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN agent_profiles.total_share_rate; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.agent_profiles.total_share_rate IS '总占成 0-100';
|
||||
|
||||
|
||||
--
|
||||
-- Name: audit_logs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.audit_logs (
|
||||
id bigint NOT NULL,
|
||||
operator_type character varying(16) NOT NULL,
|
||||
operator_id bigint DEFAULT '0'::bigint NOT NULL,
|
||||
module_code character varying(32),
|
||||
action_code character varying(32),
|
||||
target_type character varying(128),
|
||||
target_id character varying(64),
|
||||
before_json json,
|
||||
after_json json,
|
||||
ip character varying(64),
|
||||
user_agent character varying(255),
|
||||
created_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: audit_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.audit_logs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: audit_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.audit_logs_id_seq OWNED BY public.audit_logs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.cache (
|
||||
key character varying(255) NOT NULL,
|
||||
value text NOT NULL,
|
||||
expiration bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache_locks; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.cache_locks (
|
||||
key character varying(255) NOT NULL,
|
||||
owner character varying(255) NOT NULL,
|
||||
expiration bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.credit_ledger (
|
||||
id bigint NOT NULL,
|
||||
owner_type character varying(16) NOT NULL,
|
||||
owner_id bigint NOT NULL,
|
||||
amount bigint NOT NULL,
|
||||
reason character varying(64) NOT NULL,
|
||||
ref_type character varying(32),
|
||||
ref_id bigint,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.credit_ledger_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.credit_ledger_id_seq OWNED BY public.credit_ledger.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.currencies (
|
||||
id bigint NOT NULL,
|
||||
code character varying(16) NOT NULL,
|
||||
name character varying(64) NOT NULL,
|
||||
decimal_places smallint DEFAULT '2'::smallint NOT NULL,
|
||||
is_enabled boolean DEFAULT true NOT NULL,
|
||||
is_bettable boolean DEFAULT false NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.currencies_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.currencies_id_seq OWNED BY public.currencies.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.draw_result_batches (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
result_version integer NOT NULL,
|
||||
source_type character varying(16) NOT NULL,
|
||||
rng_seed_hash character varying(128),
|
||||
raw_seed_encrypted text,
|
||||
status character varying(32) NOT NULL,
|
||||
created_by bigint,
|
||||
confirmed_by bigint,
|
||||
confirmed_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN draw_result_batches.source_type; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.draw_result_batches.source_type IS 'rng|manual';
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.draw_result_batches_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.draw_result_batches_id_seq OWNED BY public.draw_result_batches.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.draw_result_items (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
result_batch_id bigint NOT NULL,
|
||||
prize_type character varying(32) NOT NULL,
|
||||
prize_index integer DEFAULT 0 NOT NULL,
|
||||
number_4d character(4) NOT NULL,
|
||||
suffix_3d character(3),
|
||||
suffix_2d character(2),
|
||||
head_digit smallint,
|
||||
tail_digit smallint,
|
||||
created_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.draw_result_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.draw_result_items_id_seq OWNED BY public.draw_result_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.draws (
|
||||
id bigint NOT NULL,
|
||||
draw_no character varying(32) NOT NULL,
|
||||
business_date date NOT NULL,
|
||||
sequence_no integer NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
start_time timestamp(0) without time zone,
|
||||
close_time timestamp(0) without time zone,
|
||||
draw_time timestamp(0) without time zone,
|
||||
cooling_end_time timestamp(0) without time zone,
|
||||
result_source character varying(16),
|
||||
current_result_version integer DEFAULT 0 NOT NULL,
|
||||
settle_version integer DEFAULT 0 NOT NULL,
|
||||
is_reopened boolean DEFAULT false NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN draws.result_source; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.draws.result_source IS 'rng|manual';
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.draws_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.draws_id_seq OWNED BY public.draws.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.failed_jobs (
|
||||
id bigint NOT NULL,
|
||||
uuid character varying(255) NOT NULL,
|
||||
connection text NOT NULL,
|
||||
queue text NOT NULL,
|
||||
payload text NOT NULL,
|
||||
exception text NOT NULL,
|
||||
failed_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.failed_jobs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.failed_jobs_id_seq OWNED BY public.failed_jobs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.jackpot_contributions (
|
||||
id bigint NOT NULL,
|
||||
jackpot_pool_id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
ticket_item_id bigint,
|
||||
contribution_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.jackpot_contributions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.jackpot_contributions_id_seq OWNED BY public.jackpot_contributions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.jackpot_payout_logs (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
jackpot_pool_id bigint NOT NULL,
|
||||
trigger_type character varying(32) NOT NULL,
|
||||
total_payout_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
winner_count integer DEFAULT 0 NOT NULL,
|
||||
trigger_snapshot_json json,
|
||||
created_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.jackpot_payout_logs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.jackpot_payout_logs_id_seq OWNED BY public.jackpot_payout_logs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.jackpot_pool_adjustments (
|
||||
id bigint NOT NULL,
|
||||
adjustment_no character varying(32) NOT NULL,
|
||||
jackpot_pool_id bigint NOT NULL,
|
||||
admin_user_id bigint NOT NULL,
|
||||
amount_delta bigint NOT NULL,
|
||||
balance_before bigint NOT NULL,
|
||||
balance_after bigint NOT NULL,
|
||||
reason character varying(500) NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN jackpot_pool_adjustments.amount_delta; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.jackpot_pool_adjustments.amount_delta IS 'signed minor units; + increase pool';
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.jackpot_pool_adjustments_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.jackpot_pool_adjustments_id_seq OWNED BY public.jackpot_pool_adjustments.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.jackpot_pools (
|
||||
id bigint NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
current_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
contribution_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
trigger_threshold bigint DEFAULT '0'::bigint NOT NULL,
|
||||
payout_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
force_trigger_draw_gap integer DEFAULT 0 NOT NULL,
|
||||
min_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status smallint DEFAULT '0'::smallint NOT NULL,
|
||||
last_trigger_draw_id bigint,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
combo_trigger_play_codes json
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN jackpot_pools.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.jackpot_pools.status IS '0=off,1=on';
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.jackpot_pools_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.jackpot_pools_id_seq OWNED BY public.jackpot_pools.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: job_batches; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.job_batches (
|
||||
id character varying(255) NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
total_jobs integer NOT NULL,
|
||||
pending_jobs integer NOT NULL,
|
||||
failed_jobs integer NOT NULL,
|
||||
failed_job_ids text NOT NULL,
|
||||
options text,
|
||||
cancelled_at integer,
|
||||
created_at integer NOT NULL,
|
||||
finished_at integer
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.jobs (
|
||||
id bigint NOT NULL,
|
||||
queue character varying(255) NOT NULL,
|
||||
payload text NOT NULL,
|
||||
attempts smallint NOT NULL,
|
||||
reserved_at integer,
|
||||
available_at integer NOT NULL,
|
||||
created_at integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.jobs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.jobs_id_seq OWNED BY public.jobs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.lottery_settings (
|
||||
id bigint NOT NULL,
|
||||
setting_key character varying(160) NOT NULL,
|
||||
value_json json NOT NULL,
|
||||
group_name character varying(64) DEFAULT 'general'::character varying NOT NULL,
|
||||
description_zh character varying(255),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN lottery_settings.group_name; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.lottery_settings.group_name IS '控制台分组展示用';
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN lottery_settings.description_zh; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.lottery_settings.description_zh IS '运维说明';
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.lottery_settings_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.lottery_settings_id_seq OWNED BY public.lottery_settings.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.migrations (
|
||||
id integer NOT NULL,
|
||||
migration character varying(255) NOT NULL,
|
||||
batch integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.migrations_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.migrations_id_seq OWNED BY public.migrations.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.odds_items (
|
||||
id bigint NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
play_code character varying(32) NOT NULL,
|
||||
prize_scope character varying(32) NOT NULL,
|
||||
odds_value bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
commission_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
extra_config_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
dimension smallint
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN odds_items.dimension; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.odds_items.dimension IS '2/3/4 维度,佣金按维度配置';
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.odds_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.odds_items_id_seq OWNED BY public.odds_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.odds_versions (
|
||||
id bigint NOT NULL,
|
||||
version_no integer NOT NULL,
|
||||
status character varying(16) NOT NULL,
|
||||
effective_at timestamp(0) without time zone,
|
||||
updated_by bigint,
|
||||
reason character varying(255),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.odds_versions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.odds_versions_id_seq OWNED BY public.odds_versions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.payment_records (
|
||||
id bigint NOT NULL,
|
||||
settlement_bill_id bigint NOT NULL,
|
||||
payer_type character varying(16) NOT NULL,
|
||||
payer_id bigint NOT NULL,
|
||||
payee_type character varying(16) NOT NULL,
|
||||
payee_id bigint NOT NULL,
|
||||
amount bigint NOT NULL,
|
||||
method character varying(32),
|
||||
status character varying(16) DEFAULT 'pending'::character varying NOT NULL,
|
||||
created_by bigint,
|
||||
confirmed_by bigint,
|
||||
confirmed_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
proof text,
|
||||
remark character varying(255)
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.payment_records_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.payment_records_id_seq OWNED BY public.payment_records.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.personal_access_tokens (
|
||||
id bigint NOT NULL,
|
||||
tokenable_type character varying(255) NOT NULL,
|
||||
tokenable_id bigint NOT NULL,
|
||||
name text NOT NULL,
|
||||
token character varying(64) NOT NULL,
|
||||
abilities text,
|
||||
last_used_at timestamp(0) without time zone,
|
||||
expires_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.personal_access_tokens_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.personal_access_tokens_id_seq OWNED BY public.personal_access_tokens.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.play_config_items (
|
||||
id bigint NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
play_code character varying(32) NOT NULL,
|
||||
is_enabled boolean DEFAULT true NOT NULL,
|
||||
min_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
max_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
display_order integer DEFAULT 0 NOT NULL,
|
||||
rule_text_zh text,
|
||||
rule_text_en text,
|
||||
rule_text_ne text,
|
||||
extra_config_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
category character varying(16),
|
||||
dimension smallint,
|
||||
bet_mode character varying(32),
|
||||
supports_multi_number boolean DEFAULT false NOT NULL,
|
||||
reserved_rule_json json,
|
||||
display_name character varying(64)
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.play_config_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.play_config_items_id_seq OWNED BY public.play_config_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.play_config_versions (
|
||||
id bigint NOT NULL,
|
||||
version_no integer NOT NULL,
|
||||
status character varying(16) NOT NULL,
|
||||
effective_at timestamp(0) without time zone,
|
||||
updated_by bigint,
|
||||
reason character varying(255),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.play_config_versions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.play_config_versions_id_seq OWNED BY public.play_config_versions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.play_types (
|
||||
id bigint NOT NULL,
|
||||
play_code character varying(32) NOT NULL,
|
||||
category character varying(16) NOT NULL,
|
||||
dimension smallint,
|
||||
bet_mode character varying(32),
|
||||
is_enabled boolean DEFAULT true NOT NULL,
|
||||
sort_order integer DEFAULT 0 NOT NULL,
|
||||
supports_multi_number boolean DEFAULT false NOT NULL,
|
||||
reserved_rule_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
display_name character varying(64)
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN play_types.dimension; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.play_types.dimension IS '2/3/4';
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.play_types_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.play_types_id_seq OWNED BY public.play_types.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_credit_accounts; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.player_credit_accounts (
|
||||
player_id bigint NOT NULL,
|
||||
credit_limit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
used_credit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
frozen_credit bigint DEFAULT '0'::bigint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.player_rebate_profiles (
|
||||
id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
game_type character varying(32) DEFAULT '*'::character varying NOT NULL,
|
||||
inherit_from_agent boolean DEFAULT true NOT NULL,
|
||||
rebate_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
extra_rebate_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.player_rebate_profiles_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.player_rebate_profiles_id_seq OWNED BY public.player_rebate_profiles.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.player_wallets (
|
||||
id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
wallet_type character varying(32) DEFAULT 'lottery'::character varying NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
balance bigint DEFAULT '0'::bigint NOT NULL,
|
||||
frozen_balance bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status smallint DEFAULT '0'::smallint NOT NULL,
|
||||
version bigint DEFAULT '0'::bigint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN player_wallets.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.player_wallets.status IS '0=active,1=frozen';
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.player_wallets_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.player_wallets_id_seq OWNED BY public.player_wallets.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: players; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.players (
|
||||
id bigint NOT NULL,
|
||||
site_code character varying(64) NOT NULL,
|
||||
site_player_id character varying(128) NOT NULL,
|
||||
username character varying(128),
|
||||
nickname character varying(128),
|
||||
default_currency character varying(16) DEFAULT 'NPR'::character varying NOT NULL,
|
||||
status smallint DEFAULT '0'::smallint NOT NULL,
|
||||
last_login_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
agent_node_id bigint,
|
||||
auth_source character varying(16) DEFAULT 'main_site_sso'::character varying NOT NULL,
|
||||
funding_mode character varying(16) DEFAULT 'wallet'::character varying NOT NULL,
|
||||
password_hash character varying(255),
|
||||
login_failed_count smallint DEFAULT '0'::smallint NOT NULL,
|
||||
login_locked_until timestamp(0) without time zone,
|
||||
risk_tags json
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN players.status; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.players.status IS '0=active,1=frozen,2=blocked';
|
||||
|
||||
|
||||
--
|
||||
-- Name: players_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.players_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: players_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.players_id_seq OWNED BY public.players.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.rebate_allocations (
|
||||
id bigint NOT NULL,
|
||||
rebate_record_id bigint NOT NULL,
|
||||
settlement_bill_id bigint,
|
||||
participant_type character varying(16) NOT NULL,
|
||||
participant_id bigint DEFAULT '0'::bigint NOT NULL,
|
||||
actual_share_rate numeric(5,2) DEFAULT '0'::numeric NOT NULL,
|
||||
allocated_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
allocation_rule character varying(32) DEFAULT 'share'::character varying NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.rebate_allocations_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.rebate_allocations_id_seq OWNED BY public.rebate_allocations.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.rebate_records (
|
||||
id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
settlement_period_id bigint,
|
||||
game_type character varying(32) DEFAULT '*'::character varying NOT NULL,
|
||||
valid_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_rate numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
rebate_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_type character varying(16) DEFAULT 'basic'::character varying NOT NULL,
|
||||
owner_agent_id bigint,
|
||||
status character varying(16) DEFAULT 'pending'::character varying NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
ticket_item_id bigint,
|
||||
reversal_of_id bigint
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.rebate_records_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.rebate_records_id_seq OWNED BY public.rebate_records.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.reconcile_items (
|
||||
id bigint NOT NULL,
|
||||
reconcile_job_id bigint NOT NULL,
|
||||
side_a_ref character varying(128),
|
||||
side_b_ref character varying(128),
|
||||
difference_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
resolved_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.reconcile_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.reconcile_items_id_seq OWNED BY public.reconcile_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.reconcile_jobs (
|
||||
id bigint NOT NULL,
|
||||
job_no character varying(64) NOT NULL,
|
||||
reconcile_type character varying(32) NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
period_start timestamp(0) without time zone,
|
||||
period_end timestamp(0) without time zone,
|
||||
summary_json json,
|
||||
finished_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
admin_user_id bigint
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.reconcile_jobs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.reconcile_jobs_id_seq OWNED BY public.reconcile_jobs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.report_jobs (
|
||||
id bigint NOT NULL,
|
||||
job_no character varying(64) NOT NULL,
|
||||
admin_user_id bigint,
|
||||
report_type character varying(64) NOT NULL,
|
||||
export_format character varying(16) DEFAULT 'csv'::character varying NOT NULL,
|
||||
filter_json json,
|
||||
status character varying(32) NOT NULL,
|
||||
output_path character varying(512),
|
||||
error_message text,
|
||||
finished_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.report_jobs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.report_jobs_id_seq OWNED BY public.report_jobs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.risk_cap_items (
|
||||
id bigint NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
draw_id bigint,
|
||||
normalized_number character(4) NOT NULL,
|
||||
cap_amount bigint NOT NULL,
|
||||
cap_type character varying(16) NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.risk_cap_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.risk_cap_items_id_seq OWNED BY public.risk_cap_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.risk_cap_versions (
|
||||
id bigint NOT NULL,
|
||||
version_no integer NOT NULL,
|
||||
status character varying(16) NOT NULL,
|
||||
effective_at timestamp(0) without time zone,
|
||||
updated_by bigint,
|
||||
reason character varying(255),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.risk_cap_versions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.risk_cap_versions_id_seq OWNED BY public.risk_cap_versions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.risk_pool_lock_logs (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
normalized_number character(4) NOT NULL,
|
||||
ticket_item_id bigint,
|
||||
action_type character varying(16) NOT NULL,
|
||||
amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
source_reason character varying(32),
|
||||
created_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.risk_pool_lock_logs_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.risk_pool_lock_logs_id_seq OWNED BY public.risk_pool_lock_logs.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.risk_pools (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
normalized_number character(4) NOT NULL,
|
||||
total_cap_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
locked_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
remaining_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
sold_out_status smallint DEFAULT '0'::smallint NOT NULL,
|
||||
version bigint DEFAULT '0'::bigint NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.risk_pools_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.risk_pools_id_seq OWNED BY public.risk_pools.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: sessions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.sessions (
|
||||
id character varying(255) NOT NULL,
|
||||
user_id bigint,
|
||||
ip_address character varying(45),
|
||||
user_agent text,
|
||||
payload text NOT NULL,
|
||||
last_activity integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.settlement_adjustments (
|
||||
id bigint NOT NULL,
|
||||
settlement_period_id bigint,
|
||||
original_bill_id bigint,
|
||||
adjustment_type character varying(32) NOT NULL,
|
||||
amount bigint NOT NULL,
|
||||
reason character varying(255),
|
||||
created_by bigint,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.settlement_adjustments_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.settlement_adjustments_id_seq OWNED BY public.settlement_adjustments.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.settlement_batches (
|
||||
id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
result_batch_id bigint NOT NULL,
|
||||
settle_version integer DEFAULT 1 NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
total_ticket_count integer DEFAULT 0 NOT NULL,
|
||||
total_win_count integer DEFAULT 0 NOT NULL,
|
||||
total_payout_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
total_jackpot_payout_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
review_status character varying(32) DEFAULT 'pending'::character varying NOT NULL,
|
||||
reviewed_by bigint,
|
||||
reviewed_at timestamp(0) without time zone,
|
||||
review_remark character varying(255),
|
||||
paid_at timestamp(0) without time zone,
|
||||
started_at timestamp(0) without time zone,
|
||||
finished_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.settlement_batches_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.settlement_batches_id_seq OWNED BY public.settlement_batches.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.settlement_bills (
|
||||
id bigint NOT NULL,
|
||||
settlement_period_id bigint NOT NULL,
|
||||
bill_type character varying(16) NOT NULL,
|
||||
owner_type character varying(16) NOT NULL,
|
||||
owner_id bigint NOT NULL,
|
||||
counterparty_type character varying(16) NOT NULL,
|
||||
counterparty_id bigint NOT NULL,
|
||||
gross_win_loss bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
adjustment_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
net_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
paid_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
unpaid_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status character varying(16) DEFAULT 'pending'::character varying NOT NULL,
|
||||
confirmed_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
locked_at timestamp(0) without time zone,
|
||||
reversed_bill_id bigint,
|
||||
meta_json json,
|
||||
platform_rounding_adjustment bigint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.settlement_bills_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.settlement_bills_id_seq OWNED BY public.settlement_bills.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.settlement_periods (
|
||||
id bigint NOT NULL,
|
||||
admin_site_id bigint NOT NULL,
|
||||
period_start timestamp(0) without time zone NOT NULL,
|
||||
period_end timestamp(0) without time zone NOT NULL,
|
||||
status character varying(16) DEFAULT 'open'::character varying NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.settlement_periods_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.settlement_periods_id_seq OWNED BY public.settlement_periods.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.share_ledger (
|
||||
id bigint NOT NULL,
|
||||
ticket_item_id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
agent_node_id bigint,
|
||||
agent_path json,
|
||||
share_snapshot json,
|
||||
game_win_loss bigint DEFAULT '0'::bigint NOT NULL,
|
||||
basic_rebate bigint DEFAULT '0'::bigint NOT NULL,
|
||||
shared_net_win_loss bigint DEFAULT '0'::bigint NOT NULL,
|
||||
allocations_json json,
|
||||
settlement_period_id bigint,
|
||||
reversal_of_id bigint,
|
||||
settled_at timestamp(0) without time zone NOT NULL,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.share_ledger_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.share_ledger_id_seq OWNED BY public.share_ledger.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.ticket_combinations (
|
||||
id bigint NOT NULL,
|
||||
ticket_item_id bigint NOT NULL,
|
||||
combination_no integer DEFAULT 0 NOT NULL,
|
||||
number_4d character(4) NOT NULL,
|
||||
bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
estimated_payout bigint DEFAULT '0'::bigint NOT NULL,
|
||||
created_at timestamp(0) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.ticket_combinations_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.ticket_combinations_id_seq OWNED BY public.ticket_combinations.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.ticket_items (
|
||||
id bigint NOT NULL,
|
||||
ticket_no character varying(64) NOT NULL,
|
||||
order_id bigint NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
original_number character varying(32),
|
||||
normalized_number character(4) NOT NULL,
|
||||
play_code character varying(32) NOT NULL,
|
||||
dimension smallint,
|
||||
digit_slot smallint,
|
||||
bet_mode character varying(32),
|
||||
unit_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
total_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
rebate_rate_snapshot numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
commission_rate_snapshot numeric(8,4) DEFAULT '0'::numeric NOT NULL,
|
||||
actual_deduct_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
odds_snapshot_json json,
|
||||
rule_snapshot_json json,
|
||||
combination_count integer DEFAULT 1 NOT NULL,
|
||||
estimated_max_payout bigint DEFAULT '0'::bigint NOT NULL,
|
||||
risk_locked_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
fail_reason_code character varying(32),
|
||||
fail_reason_text character varying(255),
|
||||
win_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
jackpot_win_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
settled_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
agent_node_id bigint,
|
||||
share_snapshot json,
|
||||
agent_rebate_rate_snapshot numeric(8,4),
|
||||
agent_settled_at timestamp(0) without time zone,
|
||||
agent_settlement_reversal_of_id bigint
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN ticket_items.dimension; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.ticket_items.dimension IS '2/3/4';
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN ticket_items.digit_slot; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.ticket_items.digit_slot IS '千百十个位,领域字典';
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.ticket_items_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.ticket_items_id_seq OWNED BY public.ticket_items.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.ticket_orders (
|
||||
id bigint NOT NULL,
|
||||
order_no character varying(64) NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
draw_id bigint NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
total_bet_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
total_rebate_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
total_actual_deduct bigint DEFAULT '0'::bigint NOT NULL,
|
||||
total_estimated_payout bigint DEFAULT '0'::bigint NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
submit_source character varying(16) DEFAULT 'h5'::character varying NOT NULL,
|
||||
client_trace_id character varying(64),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone,
|
||||
play_config_version_no integer DEFAULT 0 NOT NULL,
|
||||
odds_version_no integer DEFAULT 0 NOT NULL,
|
||||
risk_cap_version_no integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.ticket_orders_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.ticket_orders_id_seq OWNED BY public.ticket_orders.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.ticket_settlement_details (
|
||||
id bigint NOT NULL,
|
||||
settlement_batch_id bigint NOT NULL,
|
||||
ticket_item_id bigint NOT NULL,
|
||||
matched_prize_tier character varying(32),
|
||||
win_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
jackpot_allocation_amount bigint DEFAULT '0'::bigint NOT NULL,
|
||||
match_detail_json json,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.ticket_settlement_details_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.ticket_settlement_details_id_seq OWNED BY public.ticket_settlement_details.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.transfer_orders (
|
||||
id bigint NOT NULL,
|
||||
transfer_no character varying(64) NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
direction character varying(16) NOT NULL,
|
||||
currency_code character varying(16) NOT NULL,
|
||||
amount bigint NOT NULL,
|
||||
idempotent_key character varying(64) NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
external_request_payload json,
|
||||
external_response_payload json,
|
||||
external_ref_no character varying(64),
|
||||
fail_reason character varying(255),
|
||||
finished_at timestamp(0) without time zone,
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.transfer_orders_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.transfer_orders_id_seq OWNED BY public.transfer_orders.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.wallet_txns (
|
||||
id bigint NOT NULL,
|
||||
txn_no character varying(64) NOT NULL,
|
||||
player_id bigint NOT NULL,
|
||||
wallet_id bigint NOT NULL,
|
||||
biz_type character varying(32) NOT NULL,
|
||||
biz_no character varying(64),
|
||||
direction smallint NOT NULL,
|
||||
amount bigint NOT NULL,
|
||||
balance_before bigint NOT NULL,
|
||||
balance_after bigint NOT NULL,
|
||||
status character varying(32) NOT NULL,
|
||||
external_ref_no character varying(64),
|
||||
idempotent_key character varying(64),
|
||||
remark character varying(255),
|
||||
created_at timestamp(0) without time zone,
|
||||
updated_at timestamp(0) without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: COLUMN wallet_txns.direction; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON COLUMN public.wallet_txns.direction IS '1=in,2=out';
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.wallet_txns_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.wallet_txns_id_seq OWNED BY public.wallet_txns.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_action_catalog ALTER COLUMN id SET DEFAULT nextval('public.admin_action_catalog_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resource_bindings ALTER COLUMN id SET DEFAULT nextval('public.admin_api_resource_bindings_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resources ALTER COLUMN id SET DEFAULT nextval('public.admin_api_resources_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions ALTER COLUMN id SET DEFAULT nextval('public.admin_menu_actions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menus ALTER COLUMN id SET DEFAULT nextval('public.admin_menus_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles ALTER COLUMN id SET DEFAULT nextval('public.admin_roles_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_sites ALTER COLUMN id SET DEFAULT nextval('public.admin_sites_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_users ALTER COLUMN id SET DEFAULT nextval('public.admin_users_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants ALTER COLUMN id SET DEFAULT nextval('public.agent_delegation_grants_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes ALTER COLUMN id SET DEFAULT nextval('public.agent_nodes_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: audit_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.audit_logs ALTER COLUMN id SET DEFAULT nextval('public.audit_logs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.credit_ledger ALTER COLUMN id SET DEFAULT nextval('public.credit_ledger_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.currencies ALTER COLUMN id SET DEFAULT nextval('public.currencies_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches ALTER COLUMN id SET DEFAULT nextval('public.draw_result_batches_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_items ALTER COLUMN id SET DEFAULT nextval('public.draw_result_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draws ALTER COLUMN id SET DEFAULT nextval('public.draws_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.failed_jobs ALTER COLUMN id SET DEFAULT nextval('public.failed_jobs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions ALTER COLUMN id SET DEFAULT nextval('public.jackpot_contributions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_payout_logs ALTER COLUMN id SET DEFAULT nextval('public.jackpot_payout_logs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pool_adjustments ALTER COLUMN id SET DEFAULT nextval('public.jackpot_pool_adjustments_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pools ALTER COLUMN id SET DEFAULT nextval('public.jackpot_pools_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jobs ALTER COLUMN id SET DEFAULT nextval('public.jobs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.lottery_settings ALTER COLUMN id SET DEFAULT nextval('public.lottery_settings_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.migrations ALTER COLUMN id SET DEFAULT nextval('public.migrations_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_items ALTER COLUMN id SET DEFAULT nextval('public.odds_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_versions ALTER COLUMN id SET DEFAULT nextval('public.odds_versions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_records ALTER COLUMN id SET DEFAULT nextval('public.payment_records_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.personal_access_tokens ALTER COLUMN id SET DEFAULT nextval('public.personal_access_tokens_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_items ALTER COLUMN id SET DEFAULT nextval('public.play_config_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_versions ALTER COLUMN id SET DEFAULT nextval('public.play_config_versions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_types ALTER COLUMN id SET DEFAULT nextval('public.play_types_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_rebate_profiles ALTER COLUMN id SET DEFAULT nextval('public.player_rebate_profiles_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_wallets ALTER COLUMN id SET DEFAULT nextval('public.player_wallets_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: players id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.players ALTER COLUMN id SET DEFAULT nextval('public.players_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_allocations ALTER COLUMN id SET DEFAULT nextval('public.rebate_allocations_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records ALTER COLUMN id SET DEFAULT nextval('public.rebate_records_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_items ALTER COLUMN id SET DEFAULT nextval('public.reconcile_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_jobs ALTER COLUMN id SET DEFAULT nextval('public.reconcile_jobs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.report_jobs ALTER COLUMN id SET DEFAULT nextval('public.report_jobs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_items ALTER COLUMN id SET DEFAULT nextval('public.risk_cap_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_versions ALTER COLUMN id SET DEFAULT nextval('public.risk_cap_versions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pool_lock_logs ALTER COLUMN id SET DEFAULT nextval('public.risk_pool_lock_logs_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pools ALTER COLUMN id SET DEFAULT nextval('public.risk_pools_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_adjustments ALTER COLUMN id SET DEFAULT nextval('public.settlement_adjustments_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_batches ALTER COLUMN id SET DEFAULT nextval('public.settlement_batches_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_bills ALTER COLUMN id SET DEFAULT nextval('public.settlement_bills_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_periods ALTER COLUMN id SET DEFAULT nextval('public.settlement_periods_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger ALTER COLUMN id SET DEFAULT nextval('public.share_ledger_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_combinations ALTER COLUMN id SET DEFAULT nextval('public.ticket_combinations_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items ALTER COLUMN id SET DEFAULT nextval('public.ticket_items_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders ALTER COLUMN id SET DEFAULT nextval('public.ticket_orders_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_settlement_details ALTER COLUMN id SET DEFAULT nextval('public.ticket_settlement_details_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.transfer_orders ALTER COLUMN id SET DEFAULT nextval('public.transfer_orders_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns ALTER COLUMN id SET DEFAULT nextval('public.wallet_txns_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog admin_action_catalog_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_action_catalog
|
||||
ADD CONSTRAINT admin_action_catalog_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_action_catalog admin_action_catalog_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_action_catalog
|
||||
ADD CONSTRAINT admin_action_catalog_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings admin_api_resource_bindings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resource_bindings
|
||||
ADD CONSTRAINT admin_api_resource_bindings_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources admin_api_resources_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resources
|
||||
ADD CONSTRAINT admin_api_resources_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resources admin_api_resources_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resources
|
||||
ADD CONSTRAINT admin_api_resources_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions admin_menu_actions_permission_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions
|
||||
ADD CONSTRAINT admin_menu_actions_permission_code_unique UNIQUE (permission_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions admin_menu_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions
|
||||
ADD CONSTRAINT admin_menu_actions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus admin_menus_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menus
|
||||
ADD CONSTRAINT admin_menus_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus admin_menus_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menus
|
||||
ADD CONSTRAINT admin_menus_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_role_menu_actions admin_role_menu_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_role_menu_actions
|
||||
ADD CONSTRAINT admin_role_menu_actions_pkey PRIMARY KEY (role_id, menu_action_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles admin_roles_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles
|
||||
ADD CONSTRAINT admin_roles_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles admin_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles
|
||||
ADD CONSTRAINT admin_roles_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles admin_roles_slug_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles
|
||||
ADD CONSTRAINT admin_roles_slug_unique UNIQUE (slug);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites admin_sites_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_sites
|
||||
ADD CONSTRAINT admin_sites_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_sites admin_sites_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_sites
|
||||
ADD CONSTRAINT admin_sites_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agent_roles admin_user_agent_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agent_roles
|
||||
ADD CONSTRAINT admin_user_agent_roles_pkey PRIMARY KEY (admin_user_id, agent_node_id, role_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agents admin_user_agents_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agents
|
||||
ADD CONSTRAINT admin_user_agents_pkey PRIMARY KEY (admin_user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_menu_actions admin_user_menu_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_menu_actions
|
||||
ADD CONSTRAINT admin_user_menu_actions_pkey PRIMARY KEY (admin_user_id, site_id, menu_action_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_site_roles admin_user_site_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_site_roles
|
||||
ADD CONSTRAINT admin_user_site_roles_pkey PRIMARY KEY (admin_user_id, site_id, role_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users admin_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_users
|
||||
ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_users admin_users_username_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_users
|
||||
ADD CONSTRAINT admin_users_username_unique UNIQUE (username);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants agent_delegation_grants_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT agent_delegation_grants_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes agent_nodes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes
|
||||
ADD CONSTRAINT agent_nodes_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_profiles agent_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_profiles
|
||||
ADD CONSTRAINT agent_profiles_pkey PRIMARY KEY (agent_node_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: audit_logs audit_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.audit_logs
|
||||
ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache_locks cache_locks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.cache_locks
|
||||
ADD CONSTRAINT cache_locks_pkey PRIMARY KEY (key);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache cache_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.cache
|
||||
ADD CONSTRAINT cache_pkey PRIMARY KEY (key);
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger credit_ledger_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.credit_ledger
|
||||
ADD CONSTRAINT credit_ledger_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies currencies_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.currencies
|
||||
ADD CONSTRAINT currencies_code_unique UNIQUE (code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: currencies currencies_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.currencies
|
||||
ADD CONSTRAINT currencies_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches draw_result_batches_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches
|
||||
ADD CONSTRAINT draw_result_batches_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items draw_result_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_items
|
||||
ADD CONSTRAINT draw_result_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws draws_draw_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draws
|
||||
ADD CONSTRAINT draws_draw_no_unique UNIQUE (draw_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draws draws_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draws
|
||||
ADD CONSTRAINT draws_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs failed_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.failed_jobs
|
||||
ADD CONSTRAINT failed_jobs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: failed_jobs failed_jobs_uuid_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.failed_jobs
|
||||
ADD CONSTRAINT failed_jobs_uuid_unique UNIQUE (uuid);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions jackpot_contributions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT jackpot_contributions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs jackpot_payout_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_payout_logs
|
||||
ADD CONSTRAINT jackpot_payout_logs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments jackpot_pool_adjustments_adjustment_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pool_adjustments
|
||||
ADD CONSTRAINT jackpot_pool_adjustments_adjustment_no_unique UNIQUE (adjustment_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments jackpot_pool_adjustments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pool_adjustments
|
||||
ADD CONSTRAINT jackpot_pool_adjustments_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools jackpot_pools_currency_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pools
|
||||
ADD CONSTRAINT jackpot_pools_currency_code_unique UNIQUE (currency_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools jackpot_pools_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pools
|
||||
ADD CONSTRAINT jackpot_pools_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: job_batches job_batches_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.job_batches
|
||||
ADD CONSTRAINT job_batches_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jobs
|
||||
ADD CONSTRAINT jobs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings lottery_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.lottery_settings
|
||||
ADD CONSTRAINT lottery_settings_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: lottery_settings lottery_settings_setting_key_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.lottery_settings
|
||||
ADD CONSTRAINT lottery_settings_setting_key_unique UNIQUE (setting_key);
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.migrations
|
||||
ADD CONSTRAINT migrations_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items odds_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_items
|
||||
ADD CONSTRAINT odds_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions odds_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_versions
|
||||
ADD CONSTRAINT odds_versions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records payment_records_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_records
|
||||
ADD CONSTRAINT payment_records_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens personal_access_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.personal_access_tokens
|
||||
ADD CONSTRAINT personal_access_tokens_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens personal_access_tokens_token_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.personal_access_tokens
|
||||
ADD CONSTRAINT personal_access_tokens_token_unique UNIQUE (token);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items play_config_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_items
|
||||
ADD CONSTRAINT play_config_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions play_config_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_versions
|
||||
ADD CONSTRAINT play_config_versions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types play_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_types
|
||||
ADD CONSTRAINT play_types_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_types play_types_play_code_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_types
|
||||
ADD CONSTRAINT play_types_play_code_unique UNIQUE (play_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_credit_accounts player_credit_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_credit_accounts
|
||||
ADD CONSTRAINT player_credit_accounts_pkey PRIMARY KEY (player_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles player_rebate_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_rebate_profiles
|
||||
ADD CONSTRAINT player_rebate_profiles_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles player_rebate_profiles_player_id_game_type_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_rebate_profiles
|
||||
ADD CONSTRAINT player_rebate_profiles_player_id_game_type_unique UNIQUE (player_id, game_type);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets player_wallets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_wallets
|
||||
ADD CONSTRAINT player_wallets_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: players players_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.players
|
||||
ADD CONSTRAINT players_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations rebate_allocations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_allocations
|
||||
ADD CONSTRAINT rebate_allocations_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items reconcile_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_items
|
||||
ADD CONSTRAINT reconcile_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs reconcile_jobs_job_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_jobs
|
||||
ADD CONSTRAINT reconcile_jobs_job_no_unique UNIQUE (job_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs reconcile_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_jobs
|
||||
ADD CONSTRAINT reconcile_jobs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs report_jobs_job_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.report_jobs
|
||||
ADD CONSTRAINT report_jobs_job_no_unique UNIQUE (job_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs report_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.report_jobs
|
||||
ADD CONSTRAINT report_jobs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items risk_cap_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_items
|
||||
ADD CONSTRAINT risk_cap_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions risk_cap_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_versions
|
||||
ADD CONSTRAINT risk_cap_versions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs risk_pool_lock_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pool_lock_logs
|
||||
ADD CONSTRAINT risk_pool_lock_logs_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools risk_pools_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pools
|
||||
ADD CONSTRAINT risk_pools_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.sessions
|
||||
ADD CONSTRAINT sessions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments settlement_adjustments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_adjustments
|
||||
ADD CONSTRAINT settlement_adjustments_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches settlement_batches_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_batches
|
||||
ADD CONSTRAINT settlement_batches_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills settlement_bills_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_bills
|
||||
ADD CONSTRAINT settlement_bills_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods settlement_periods_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_periods
|
||||
ADD CONSTRAINT settlement_periods_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations ticket_combinations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_combinations
|
||||
ADD CONSTRAINT ticket_combinations_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_ticket_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_ticket_no_unique UNIQUE (ticket_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders ticket_orders_order_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders
|
||||
ADD CONSTRAINT ticket_orders_order_no_unique UNIQUE (order_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders ticket_orders_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders
|
||||
ADD CONSTRAINT ticket_orders_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details ticket_settlement_details_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_settlement_details
|
||||
ADD CONSTRAINT ticket_settlement_details_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders transfer_orders_idempotent_key_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.transfer_orders
|
||||
ADD CONSTRAINT transfer_orders_idempotent_key_unique UNIQUE (idempotent_key);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders transfer_orders_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.transfer_orders
|
||||
ADD CONSTRAINT transfer_orders_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders transfer_orders_transfer_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.transfer_orders
|
||||
ADD CONSTRAINT transfer_orders_transfer_no_unique UNIQUE (transfer_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings uk_admin_api_bindings_api_action; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resource_bindings
|
||||
ADD CONSTRAINT uk_admin_api_bindings_api_action UNIQUE (api_resource_id, menu_action_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions uk_admin_menu_actions_menu_action; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions
|
||||
ADD CONSTRAINT uk_admin_menu_actions_menu_action UNIQUE (menu_id, action_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants uk_agent_delegation_child_action; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT uk_agent_delegation_child_action UNIQUE (child_agent_id, menu_action_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes uk_agent_nodes_site_code; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes
|
||||
ADD CONSTRAINT uk_agent_nodes_site_code UNIQUE (admin_site_id, code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches uk_draw_result_batches_draw_version; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches
|
||||
ADD CONSTRAINT uk_draw_result_batches_draw_version UNIQUE (draw_id, result_version);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions uk_jackpot_contributions_ticket_item; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT uk_jackpot_contributions_ticket_item UNIQUE (ticket_item_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items uk_odds_items_version_play_prize_currency_dimension; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_items
|
||||
ADD CONSTRAINT uk_odds_items_version_play_prize_currency_dimension UNIQUE (version_id, play_code, prize_scope, currency_code, dimension);
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items uk_play_config_items_version_play; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_items
|
||||
ADD CONSTRAINT uk_play_config_items_version_play UNIQUE (version_id, play_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets uk_player_wallets_player_type_currency; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_wallets
|
||||
ADD CONSTRAINT uk_player_wallets_player_type_currency UNIQUE (player_id, wallet_type, currency_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: players uk_players_site_player; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.players
|
||||
ADD CONSTRAINT uk_players_site_player UNIQUE (site_code, site_player_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools uk_risk_pools_draw_number; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pools
|
||||
ADD CONSTRAINT uk_risk_pools_draw_number UNIQUE (draw_id, normalized_number);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details uk_ticket_settlement_batch_ticket; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_settlement_details
|
||||
ADD CONSTRAINT uk_ticket_settlement_batch_ticket UNIQUE (settlement_batch_id, ticket_item_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns uk_wallet_txns_idempotent_biz; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns
|
||||
ADD CONSTRAINT uk_wallet_txns_idempotent_biz UNIQUE (idempotent_key, biz_type);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders uniq_ticket_orders_player_draw_trace; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders
|
||||
ADD CONSTRAINT uniq_ticket_orders_player_draw_trace UNIQUE (player_id, draw_id, client_trace_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns wallet_txns_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns
|
||||
ADD CONSTRAINT wallet_txns_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns wallet_txns_txn_no_unique; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns
|
||||
ADD CONSTRAINT wallet_txns_txn_no_unique UNIQUE (txn_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache_expiration_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX cache_expiration_index ON public.cache USING btree (expiration);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cache_locks_expiration_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX cache_locks_expiration_index ON public.cache_locks USING btree (expiration);
|
||||
|
||||
|
||||
--
|
||||
-- Name: credit_ledger_owner_type_owner_id_created_at_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX credit_ledger_owner_type_owner_id_created_at_index ON public.credit_ledger USING btree (owner_type, owner_id, created_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_admin_api_resources_module_status; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_admin_api_resources_module_status ON public.admin_api_resources USING btree (module_code, status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_admin_menu_actions_menu_status; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_admin_menu_actions_menu_status ON public.admin_menu_actions USING btree (menu_id, status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_admin_menus_parent_sort; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_admin_menus_parent_sort ON public.admin_menus USING btree (parent_id, sort_order);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_agent_delegation_parent_child; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_agent_delegation_parent_child ON public.agent_delegation_grants USING btree (parent_agent_id, child_agent_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_agent_nodes_path; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_agent_nodes_path ON public.agent_nodes USING btree (path);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_agent_nodes_site_parent; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_agent_nodes_site_parent ON public.agent_nodes USING btree (admin_site_id, parent_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_audit_logs_module_action; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_audit_logs_module_action ON public.audit_logs USING btree (module_code, action_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_audit_logs_operator_time; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_audit_logs_operator_time ON public.audit_logs USING btree (operator_type, operator_id, created_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_draw_result_items_batch_prize; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_draw_result_items_batch_prize ON public.draw_result_items USING btree (result_batch_id, prize_type, prize_index);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_draw_result_items_draw_number; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_draw_result_items_draw_number ON public.draw_result_items USING btree (draw_id, number_4d);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_draw_result_items_draw_prize; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_draw_result_items_draw_prize ON public.draw_result_items USING btree (draw_id, prize_type, prize_index);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_draws_business_date_draw_time; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_draws_business_date_draw_time ON public.draws USING btree (business_date, draw_time);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_draws_status_draw_time; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_draws_status_draw_time ON public.draws USING btree (status, draw_time);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_jackpot_contrib_draw_player; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_jackpot_contrib_draw_player ON public.jackpot_contributions USING btree (draw_id, player_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_jackpot_pool_adjustments_pool_created; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_jackpot_pool_adjustments_pool_created ON public.jackpot_pool_adjustments USING btree (jackpot_pool_id, created_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_lottery_settings_group; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_lottery_settings_group ON public.lottery_settings USING btree (group_name);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_odds_items_version_play; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_odds_items_version_play ON public.odds_items USING btree (version_id, play_code);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_players_site_agent; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_players_site_agent ON public.players USING btree (site_code, agent_node_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_players_site_auth_username; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_players_site_auth_username ON public.players USING btree (site_code, auth_source, username);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_players_status; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_players_status ON public.players USING btree (status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_risk_cap_items_lookup; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_risk_cap_items_lookup ON public.risk_cap_items USING btree (version_id, draw_id, normalized_number);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_risk_lock_logs_draw_number; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_risk_lock_logs_draw_number ON public.risk_pool_lock_logs USING btree (draw_id, normalized_number);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_risk_pools_draw_soldout; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_risk_pools_draw_soldout ON public.risk_pools USING btree (draw_id, sold_out_status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_settlement_batches_draw_version; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_settlement_batches_draw_version ON public.settlement_batches USING btree (draw_id, settle_version);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_settlement_batches_result_batch_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_settlement_batches_result_batch_id ON public.settlement_batches USING btree (result_batch_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_combinations_item; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_combinations_item ON public.ticket_combinations USING btree (ticket_item_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_combinations_number; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_combinations_number ON public.ticket_combinations USING btree (number_4d);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_items_draw_number; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_items_draw_number ON public.ticket_items USING btree (draw_id, normalized_number);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_items_draw_status; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_items_draw_status ON public.ticket_items USING btree (draw_id, status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_items_order_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_items_order_id ON public.ticket_items USING btree (order_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_items_player_draw; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_items_player_draw ON public.ticket_items USING btree (player_id, draw_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_items_player_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_items_player_id ON public.ticket_items USING btree (player_id, id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_orders_draw_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_orders_draw_id ON public.ticket_orders USING btree (draw_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_orders_player_draw; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_orders_player_draw ON public.ticket_orders USING btree (player_id, draw_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_ticket_settlement_details_ticket_item; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_ticket_settlement_details_ticket_item ON public.ticket_settlement_details USING btree (ticket_item_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_wallet_txns_biz; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_wallet_txns_biz ON public.wallet_txns USING btree (biz_type, biz_no);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_wallet_txns_player_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_wallet_txns_player_id ON public.wallet_txns USING btree (player_id, id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: idx_wallet_txns_player_time; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX idx_wallet_txns_player_time ON public.wallet_txns USING btree (player_id, created_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: jobs_queue_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX jobs_queue_index ON public.jobs USING btree (queue);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens_expires_at_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX personal_access_tokens_expires_at_index ON public.personal_access_tokens USING btree (expires_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: personal_access_tokens_tokenable_type_tokenable_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX personal_access_tokens_tokenable_type_tokenable_id_index ON public.personal_access_tokens USING btree (tokenable_type, tokenable_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: sessions_last_activity_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX sessions_last_activity_index ON public.sessions USING btree (last_activity);
|
||||
|
||||
|
||||
--
|
||||
-- Name: sessions_user_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX sessions_user_id_index ON public.sessions USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills_settlement_period_id_bill_type_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX settlement_bills_settlement_period_id_bill_type_index ON public.settlement_bills USING btree (settlement_period_id, bill_type);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods_admin_site_id_status_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX settlement_periods_admin_site_id_status_index ON public.settlement_periods USING btree (admin_site_id, status);
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger_settled_at_player_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX share_ledger_settled_at_player_id_index ON public.share_ledger USING btree (settled_at, player_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger_settlement_period_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX share_ledger_settlement_period_id_index ON public.share_ledger USING btree (settlement_period_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders_player_id_created_at_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX transfer_orders_player_id_created_at_index ON public.transfer_orders USING btree (player_id, created_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings admin_api_resource_bindings_api_resource_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resource_bindings
|
||||
ADD CONSTRAINT admin_api_resource_bindings_api_resource_id_foreign FOREIGN KEY (api_resource_id) REFERENCES public.admin_api_resources(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_api_resource_bindings admin_api_resource_bindings_menu_action_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_api_resource_bindings
|
||||
ADD CONSTRAINT admin_api_resource_bindings_menu_action_id_foreign FOREIGN KEY (menu_action_id) REFERENCES public.admin_menu_actions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions admin_menu_actions_action_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions
|
||||
ADD CONSTRAINT admin_menu_actions_action_id_foreign FOREIGN KEY (action_id) REFERENCES public.admin_action_catalog(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menu_actions admin_menu_actions_menu_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menu_actions
|
||||
ADD CONSTRAINT admin_menu_actions_menu_id_foreign FOREIGN KEY (menu_id) REFERENCES public.admin_menus(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_menus admin_menus_parent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_menus
|
||||
ADD CONSTRAINT admin_menus_parent_id_foreign FOREIGN KEY (parent_id) REFERENCES public.admin_menus(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_role_menu_actions admin_role_menu_actions_menu_action_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_role_menu_actions
|
||||
ADD CONSTRAINT admin_role_menu_actions_menu_action_id_foreign FOREIGN KEY (menu_action_id) REFERENCES public.admin_menu_actions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_role_menu_actions admin_role_menu_actions_role_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_role_menu_actions
|
||||
ADD CONSTRAINT admin_role_menu_actions_role_id_foreign FOREIGN KEY (role_id) REFERENCES public.admin_roles(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles admin_roles_delegated_from_role_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles
|
||||
ADD CONSTRAINT admin_roles_delegated_from_role_id_foreign FOREIGN KEY (delegated_from_role_id) REFERENCES public.admin_roles(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_roles admin_roles_owner_agent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_roles
|
||||
ADD CONSTRAINT admin_roles_owner_agent_id_foreign FOREIGN KEY (owner_agent_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agent_roles admin_user_agent_roles_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agent_roles
|
||||
ADD CONSTRAINT admin_user_agent_roles_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agent_roles admin_user_agent_roles_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agent_roles
|
||||
ADD CONSTRAINT admin_user_agent_roles_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agent_roles admin_user_agent_roles_role_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agent_roles
|
||||
ADD CONSTRAINT admin_user_agent_roles_role_id_foreign FOREIGN KEY (role_id) REFERENCES public.admin_roles(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agents admin_user_agents_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agents
|
||||
ADD CONSTRAINT admin_user_agents_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_agents admin_user_agents_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_agents
|
||||
ADD CONSTRAINT admin_user_agents_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_menu_actions admin_user_menu_actions_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_menu_actions
|
||||
ADD CONSTRAINT admin_user_menu_actions_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_menu_actions admin_user_menu_actions_menu_action_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_menu_actions
|
||||
ADD CONSTRAINT admin_user_menu_actions_menu_action_id_foreign FOREIGN KEY (menu_action_id) REFERENCES public.admin_menu_actions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_menu_actions admin_user_menu_actions_site_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_menu_actions
|
||||
ADD CONSTRAINT admin_user_menu_actions_site_id_foreign FOREIGN KEY (site_id) REFERENCES public.admin_sites(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_site_roles admin_user_site_roles_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_site_roles
|
||||
ADD CONSTRAINT admin_user_site_roles_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_site_roles admin_user_site_roles_role_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_site_roles
|
||||
ADD CONSTRAINT admin_user_site_roles_role_id_foreign FOREIGN KEY (role_id) REFERENCES public.admin_roles(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: admin_user_site_roles admin_user_site_roles_site_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_site_roles
|
||||
ADD CONSTRAINT admin_user_site_roles_site_id_foreign FOREIGN KEY (site_id) REFERENCES public.admin_sites(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants agent_delegation_grants_child_agent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT agent_delegation_grants_child_agent_id_foreign FOREIGN KEY (child_agent_id) REFERENCES public.agent_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants agent_delegation_grants_granted_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT agent_delegation_grants_granted_by_foreign FOREIGN KEY (granted_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants agent_delegation_grants_menu_action_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT agent_delegation_grants_menu_action_id_foreign FOREIGN KEY (menu_action_id) REFERENCES public.admin_menu_actions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_delegation_grants agent_delegation_grants_parent_agent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_delegation_grants
|
||||
ADD CONSTRAINT agent_delegation_grants_parent_agent_id_foreign FOREIGN KEY (parent_agent_id) REFERENCES public.agent_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes agent_nodes_admin_site_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes
|
||||
ADD CONSTRAINT agent_nodes_admin_site_id_foreign FOREIGN KEY (admin_site_id) REFERENCES public.admin_sites(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes agent_nodes_created_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes
|
||||
ADD CONSTRAINT agent_nodes_created_by_foreign FOREIGN KEY (created_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_nodes agent_nodes_parent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_nodes
|
||||
ADD CONSTRAINT agent_nodes_parent_id_foreign FOREIGN KEY (parent_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: agent_profiles agent_profiles_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.agent_profiles
|
||||
ADD CONSTRAINT agent_profiles_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches draw_result_batches_confirmed_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches
|
||||
ADD CONSTRAINT draw_result_batches_confirmed_by_foreign FOREIGN KEY (confirmed_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches draw_result_batches_created_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches
|
||||
ADD CONSTRAINT draw_result_batches_created_by_foreign FOREIGN KEY (created_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_batches draw_result_batches_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_batches
|
||||
ADD CONSTRAINT draw_result_batches_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items draw_result_items_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_items
|
||||
ADD CONSTRAINT draw_result_items_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: draw_result_items draw_result_items_result_batch_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.draw_result_items
|
||||
ADD CONSTRAINT draw_result_items_result_batch_id_foreign FOREIGN KEY (result_batch_id) REFERENCES public.draw_result_batches(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions jackpot_contributions_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT jackpot_contributions_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions jackpot_contributions_jackpot_pool_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT jackpot_contributions_jackpot_pool_id_foreign FOREIGN KEY (jackpot_pool_id) REFERENCES public.jackpot_pools(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions jackpot_contributions_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT jackpot_contributions_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_contributions jackpot_contributions_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_contributions
|
||||
ADD CONSTRAINT jackpot_contributions_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs jackpot_payout_logs_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_payout_logs
|
||||
ADD CONSTRAINT jackpot_payout_logs_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_payout_logs jackpot_payout_logs_jackpot_pool_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_payout_logs
|
||||
ADD CONSTRAINT jackpot_payout_logs_jackpot_pool_id_foreign FOREIGN KEY (jackpot_pool_id) REFERENCES public.jackpot_pools(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments jackpot_pool_adjustments_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pool_adjustments
|
||||
ADD CONSTRAINT jackpot_pool_adjustments_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pool_adjustments jackpot_pool_adjustments_jackpot_pool_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pool_adjustments
|
||||
ADD CONSTRAINT jackpot_pool_adjustments_jackpot_pool_id_foreign FOREIGN KEY (jackpot_pool_id) REFERENCES public.jackpot_pools(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: jackpot_pools jackpot_pools_last_trigger_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.jackpot_pools
|
||||
ADD CONSTRAINT jackpot_pools_last_trigger_draw_id_foreign FOREIGN KEY (last_trigger_draw_id) REFERENCES public.draws(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_items odds_items_version_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_items
|
||||
ADD CONSTRAINT odds_items_version_id_foreign FOREIGN KEY (version_id) REFERENCES public.odds_versions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: odds_versions odds_versions_updated_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.odds_versions
|
||||
ADD CONSTRAINT odds_versions_updated_by_foreign FOREIGN KEY (updated_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records payment_records_confirmed_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_records
|
||||
ADD CONSTRAINT payment_records_confirmed_by_foreign FOREIGN KEY (confirmed_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records payment_records_created_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_records
|
||||
ADD CONSTRAINT payment_records_created_by_foreign FOREIGN KEY (created_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_records payment_records_settlement_bill_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_records
|
||||
ADD CONSTRAINT payment_records_settlement_bill_id_foreign FOREIGN KEY (settlement_bill_id) REFERENCES public.settlement_bills(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_items play_config_items_version_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_items
|
||||
ADD CONSTRAINT play_config_items_version_id_foreign FOREIGN KEY (version_id) REFERENCES public.play_config_versions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: play_config_versions play_config_versions_updated_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.play_config_versions
|
||||
ADD CONSTRAINT play_config_versions_updated_by_foreign FOREIGN KEY (updated_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_credit_accounts player_credit_accounts_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_credit_accounts
|
||||
ADD CONSTRAINT player_credit_accounts_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_rebate_profiles player_rebate_profiles_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_rebate_profiles
|
||||
ADD CONSTRAINT player_rebate_profiles_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: player_wallets player_wallets_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.player_wallets
|
||||
ADD CONSTRAINT player_wallets_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: players players_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.players
|
||||
ADD CONSTRAINT players_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations rebate_allocations_rebate_record_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_allocations
|
||||
ADD CONSTRAINT rebate_allocations_rebate_record_id_foreign FOREIGN KEY (rebate_record_id) REFERENCES public.rebate_records(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_allocations rebate_allocations_settlement_bill_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_allocations
|
||||
ADD CONSTRAINT rebate_allocations_settlement_bill_id_foreign FOREIGN KEY (settlement_bill_id) REFERENCES public.settlement_bills(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_owner_agent_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_owner_agent_id_foreign FOREIGN KEY (owner_agent_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_reversal_of_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_reversal_of_id_foreign FOREIGN KEY (reversal_of_id) REFERENCES public.rebate_records(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_settlement_period_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_settlement_period_id_foreign FOREIGN KEY (settlement_period_id) REFERENCES public.settlement_periods(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: rebate_records rebate_records_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.rebate_records
|
||||
ADD CONSTRAINT rebate_records_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_items reconcile_items_reconcile_job_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_items
|
||||
ADD CONSTRAINT reconcile_items_reconcile_job_id_foreign FOREIGN KEY (reconcile_job_id) REFERENCES public.reconcile_jobs(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: reconcile_jobs reconcile_jobs_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.reconcile_jobs
|
||||
ADD CONSTRAINT reconcile_jobs_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: report_jobs report_jobs_admin_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.report_jobs
|
||||
ADD CONSTRAINT report_jobs_admin_user_id_foreign FOREIGN KEY (admin_user_id) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items risk_cap_items_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_items
|
||||
ADD CONSTRAINT risk_cap_items_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_items risk_cap_items_version_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_items
|
||||
ADD CONSTRAINT risk_cap_items_version_id_foreign FOREIGN KEY (version_id) REFERENCES public.risk_cap_versions(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_cap_versions risk_cap_versions_updated_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_cap_versions
|
||||
ADD CONSTRAINT risk_cap_versions_updated_by_foreign FOREIGN KEY (updated_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs risk_pool_lock_logs_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pool_lock_logs
|
||||
ADD CONSTRAINT risk_pool_lock_logs_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pool_lock_logs risk_pool_lock_logs_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pool_lock_logs
|
||||
ADD CONSTRAINT risk_pool_lock_logs_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: risk_pools risk_pools_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.risk_pools
|
||||
ADD CONSTRAINT risk_pools_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments settlement_adjustments_created_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_adjustments
|
||||
ADD CONSTRAINT settlement_adjustments_created_by_foreign FOREIGN KEY (created_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments settlement_adjustments_original_bill_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_adjustments
|
||||
ADD CONSTRAINT settlement_adjustments_original_bill_id_foreign FOREIGN KEY (original_bill_id) REFERENCES public.settlement_bills(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_adjustments settlement_adjustments_settlement_period_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_adjustments
|
||||
ADD CONSTRAINT settlement_adjustments_settlement_period_id_foreign FOREIGN KEY (settlement_period_id) REFERENCES public.settlement_periods(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches settlement_batches_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_batches
|
||||
ADD CONSTRAINT settlement_batches_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches settlement_batches_result_batch_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_batches
|
||||
ADD CONSTRAINT settlement_batches_result_batch_id_foreign FOREIGN KEY (result_batch_id) REFERENCES public.draw_result_batches(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_batches settlement_batches_reviewed_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_batches
|
||||
ADD CONSTRAINT settlement_batches_reviewed_by_foreign FOREIGN KEY (reviewed_by) REFERENCES public.admin_users(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills settlement_bills_reversed_bill_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_bills
|
||||
ADD CONSTRAINT settlement_bills_reversed_bill_id_foreign FOREIGN KEY (reversed_bill_id) REFERENCES public.settlement_bills(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_bills settlement_bills_settlement_period_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_bills
|
||||
ADD CONSTRAINT settlement_bills_settlement_period_id_foreign FOREIGN KEY (settlement_period_id) REFERENCES public.settlement_periods(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settlement_periods settlement_periods_admin_site_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settlement_periods
|
||||
ADD CONSTRAINT settlement_periods_admin_site_id_foreign FOREIGN KEY (admin_site_id) REFERENCES public.admin_sites(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_reversal_of_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_reversal_of_id_foreign FOREIGN KEY (reversal_of_id) REFERENCES public.share_ledger(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_settlement_period_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_settlement_period_id_foreign FOREIGN KEY (settlement_period_id) REFERENCES public.settlement_periods(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: share_ledger share_ledger_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.share_ledger
|
||||
ADD CONSTRAINT share_ledger_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_combinations ticket_combinations_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_combinations
|
||||
ADD CONSTRAINT ticket_combinations_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_agent_node_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_agent_node_id_foreign FOREIGN KEY (agent_node_id) REFERENCES public.agent_nodes(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_agent_settlement_reversal_of_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_agent_settlement_reversal_of_id_foreign FOREIGN KEY (agent_settlement_reversal_of_id) REFERENCES public.ticket_items(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_order_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_order_id_foreign FOREIGN KEY (order_id) REFERENCES public.ticket_orders(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_items ticket_items_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_items
|
||||
ADD CONSTRAINT ticket_items_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders ticket_orders_draw_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders
|
||||
ADD CONSTRAINT ticket_orders_draw_id_foreign FOREIGN KEY (draw_id) REFERENCES public.draws(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_orders ticket_orders_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_orders
|
||||
ADD CONSTRAINT ticket_orders_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details ticket_settlement_details_settlement_batch_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_settlement_details
|
||||
ADD CONSTRAINT ticket_settlement_details_settlement_batch_id_foreign FOREIGN KEY (settlement_batch_id) REFERENCES public.settlement_batches(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: ticket_settlement_details ticket_settlement_details_ticket_item_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.ticket_settlement_details
|
||||
ADD CONSTRAINT ticket_settlement_details_ticket_item_id_foreign FOREIGN KEY (ticket_item_id) REFERENCES public.ticket_items(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: transfer_orders transfer_orders_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.transfer_orders
|
||||
ADD CONSTRAINT transfer_orders_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns wallet_txns_player_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns
|
||||
ADD CONSTRAINT wallet_txns_player_id_foreign FOREIGN KEY (player_id) REFERENCES public.players(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: wallet_txns wallet_txns_wallet_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.wallet_txns
|
||||
ADD CONSTRAINT wallet_txns_wallet_id_foreign FOREIGN KEY (wallet_id) REFERENCES public.player_wallets(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict rPXEgF1VaYgsz0ptn4X1KcYROWRPYlYb6daN4zAOY961hMNjxCs5gLhsUZO9N0E
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
\restrict RiLJxG2okqJB0Ghnyl7nmKPp6kFTgq0lQmAb7r3CeeShjxRjgjZVfbJ1VM9V1oB
|
||||
|
||||
-- Dumped from database version 18.3(ServBay)
|
||||
-- Dumped by pg_dump version 18.3(ServBay)
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET transaction_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
--
|
||||
-- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COPY public.migrations (id, migration, batch) FROM stdin;
|
||||
1 0001_01_01_000000_create_users_table 1
|
||||
2 0001_01_01_000001_create_cache_table 1
|
||||
3 0001_01_01_000002_create_jobs_table 1
|
||||
4 2026_05_08_100000_create_currencies_table 1
|
||||
5 2026_05_08_100001_create_players_table 1
|
||||
6 2026_05_08_100002_create_admin_users_table 1
|
||||
7 2026_05_08_100003_create_admin_roles_and_permissions_tables 1
|
||||
8 2026_05_08_100004_create_player_wallets_table 1
|
||||
9 2026_05_08_100005_create_wallet_txns_table 1
|
||||
10 2026_05_08_100006_create_transfer_orders_table 1
|
||||
11 2026_05_08_100007_create_draws_table 1
|
||||
12 2026_05_08_100008_create_draw_result_batches_table 1
|
||||
13 2026_05_08_100009_create_draw_result_items_table 1
|
||||
14 2026_05_08_120000_drop_laravel_default_users_and_password_reset_tables 1
|
||||
15 2026_05_08_130000_create_play_types_table 1
|
||||
16 2026_05_08_130001_create_play_config_versions_and_items_tables 1
|
||||
17 2026_05_08_130002_create_odds_versions_and_items_tables 1
|
||||
18 2026_05_08_130003_create_risk_cap_versions_and_items_tables 1
|
||||
19 2026_05_08_130004_create_ticket_orders_table 1
|
||||
20 2026_05_08_130005_create_ticket_items_table 1
|
||||
21 2026_05_08_130006_create_ticket_combinations_table 1
|
||||
22 2026_05_08_130007_create_risk_pools_and_lock_logs_tables 1
|
||||
23 2026_05_08_130008_create_settlement_and_jackpot_tables 1
|
||||
24 2026_05_08_130009_create_report_audit_reconcile_tables 1
|
||||
25 2026_05_08_140000_create_lottery_settings_table 1
|
||||
26 2026_05_09_023835_create_personal_access_tokens_table 1
|
||||
27 2026_05_09_119999_rename_duplicate_migration_filenames_in_table 1
|
||||
28 2026_05_09_120001_add_username_and_nullable_email_to_admin_users 1
|
||||
29 2026_05_09_120002_migrate_draw_status_to_domain_dict 1
|
||||
30 2026_05_11_120000_add_admin_user_id_to_reconcile_jobs_table 1
|
||||
31 2026_05_11_173000_create_admin_user_permissions_table 1
|
||||
32 2026_05_13_100000_rebuild_admin_authorization_system 1
|
||||
33 2026_05_16_000100_add_snapshot_columns_to_play_config_items_table 1
|
||||
34 2026_05_18_000001_add_combo_trigger_to_jackpot_pools_table 1
|
||||
35 2026_05_18_090000_add_config_version_snapshots_to_ticket_orders 1
|
||||
36 2026_05_18_120000_sync_complete_admin_api_resources 1
|
||||
37 2026_05_19_112752_seed_default_jackpot_pools 1
|
||||
38 2026_05_19_120000_create_admin_role_legacy_permissions_table 1
|
||||
39 2026_05_19_121000_sync_admin_role_manage_permission 1
|
||||
40 2026_05_19_122000_sync_player_permission_resource_bindings 1
|
||||
41 2026_05_20_000001_add_admin_ticket_items_api_resource 1
|
||||
42 2026_05_21_000002_add_admin_currency_api_resources 1
|
||||
43 2026_05_21_093141_add_dimension_to_odds_items_table 1
|
||||
44 2026_05_21_150000_add_admin_currency_destroy_api_resource 1
|
||||
45 2026_05_21_160000_add_currency_manage_legacy_permission 1
|
||||
46 2026_05_21_170000_move_currency_menu_to_top_level_route 1
|
||||
47 2026_05_22_100000_add_admin_report_module 1
|
||||
48 2026_05_22_110000_fix_admin_report_authorization 1
|
||||
49 2026_05_22_120000_drop_redundant_admin_and_system_tables 1
|
||||
50 2026_05_22_130000_consolidate_admin_rbac_slugs 1
|
||||
51 2026_05_22_140000_add_frontend_play_rules_html_i18n_settings 1
|
||||
52 2026_05_25_120001_consolidate_play_display_name_columns 1
|
||||
53 2026_05_25_120002_expand_audit_logs_target_type 1
|
||||
54 2026_05_25_120003_refine_admin_permission_granularity 1
|
||||
55 2026_05_25_130000_remove_stale_admin_menu_actions 1
|
||||
56 2026_05_25_140000_add_admin_dashboard_analytics_resource 1
|
||||
57 2026_05_25_180000_add_settlement_batch_review_columns 1
|
||||
58 2026_05_26_100000_expand_admin_permission_granularity 1
|
||||
59 2026_05_27_100000_add_jackpot_manual_burst_permission 1
|
||||
60 2026_05_28_100000_resync_admin_api_resources_after_dashboard_view 2
|
||||
61 2026_05_29_100000_add_unique_ticket_item_id_to_jackpot_contributions 3
|
||||
62 2026_05_30_100000_create_jackpot_pool_adjustments_table 4
|
||||
63 2026_05_30_100001_add_jackpot_pool_adjustment_api_resources 5
|
||||
64 2026_05_26_120000_add_unique_client_trace_to_ticket_orders 6
|
||||
65 2026_05_27_140000_add_integration_fields_to_admin_sites 6
|
||||
66 2026_05_27_140001_seed_integration_menu_actions 7
|
||||
67 2026_05_31_100000_add_query_performance_indexes 8
|
||||
68 2026_06_01_100000_add_admin_settings_batch_update_api_resource 8
|
||||
69 2026_06_02_100000_create_agent_hierarchy_tables 8
|
||||
70 2026_06_02_100001_seed_agent_node_permissions 8
|
||||
71 2026_06_02_110000_agent_scoped_roles_and_player_agent 8
|
||||
72 2026_06_02_110001_seed_agent_role_permissions 8
|
||||
73 2026_06_02_120000_create_agent_delegation_grants 8
|
||||
74 2026_06_02_130000_backfill_players_agent_node_id 9
|
||||
75 2026_06_03_140000_ensure_agent_admin_user_destroy_api_resource 10
|
||||
76 2026_06_03_120000_split_agent_permission_granularity 11
|
||||
77 2026_06_03_150000_align_root_agent_codes 12
|
||||
78 2026_06_03_160000_agent_credit_and_settlement_tables 12
|
||||
79 2026_06_03_170000_seed_agent_settlement_api_resources 13
|
||||
80 2026_06_03_180000_add_agent_profile_capability_flags 14
|
||||
81 2026_06_03_190000_fix_agent_primary_admin_user_status 15
|
||||
82 2026_06_04_100000_agent_game_settlement_ledger 16
|
||||
83 2026_06_04_120000_resync_agent_owner_role_permissions 16
|
||||
84 2026_06_04_130000_seed_platform_agent_role_and_resync_bindings 16
|
||||
85 2026_06_04_140000_bind_agents_to_platform_agent_role 17
|
||||
86 2026_06_04_120000_add_player_auth_and_funding_mode 18
|
||||
87 2026_06_04_120000_agent_settlement_payment_proof 19
|
||||
88 2026_06_04_140000_agent_settlement_reports_and_tags 20
|
||||
89 2026_06_04_150000_ensure_platform_fixed_system_roles 20
|
||||
90 2026_06_05_120000_seed_credit_ledger_admin_api_resource 21
|
||||
\.
|
||||
|
||||
|
||||
--
|
||||
-- Name: migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('public.migrations_id_seq', 90, true);
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict RiLJxG2okqJB0Ghnyl7nmKPp6kFTgq0lQmAb7r3CeeShjxRjgjZVfbJ1VM9V1oB
|
||||
|
||||
@@ -19,6 +19,7 @@ return [
|
||||
'player_already_registered' => 'This main-site player is already registered.',
|
||||
'player_wallet_balance_blocks_delete' => 'Player wallet still has balance. Clear it before deletion.',
|
||||
'player_has_tickets_blocks_delete' => 'Player has ticket records and cannot be deleted.',
|
||||
'player_unpaid_settlement_blocks_delete' => 'Player still has unpaid settlement bills and cannot be deleted until they are settled or written off.',
|
||||
'role_cannot_delete_super_admin' => 'Cannot delete the super admin role.',
|
||||
'platform_roles_fixed' => 'Only the built-in Super Admin and Agent platform roles are supported; creating new roles is disabled.',
|
||||
'role_super_admin_permissions_fixed' => 'Super Admin always has full permissions. Run lottery:admin-auth-sync after the permission catalog changes.',
|
||||
|
||||
@@ -19,6 +19,7 @@ return [
|
||||
'player_already_registered' => 'यो मुख्य साइट खेलाडी पहिले नै दर्ता भइसकेको छ।',
|
||||
'player_wallet_balance_blocks_delete' => 'खेलाडी वालेटमा ब्यालेन्स छ, मेटाउनु अघि खाली गर्नुहोस्।',
|
||||
'player_has_tickets_blocks_delete' => 'खेलाडीसँग टिकट रेकर्ड छ, मेटाउन मिल्दैन।',
|
||||
'player_unpaid_settlement_blocks_delete' => 'खेलाडीसँग अझै बाँकी सेटलमेन्ट बिलहरू छन्। पहिले सेटल वा राइट-अफ गरेपछि मात्र मेटाउन मिल्छ।',
|
||||
'role_cannot_delete_super_admin' => 'सुपर एडमिन भूमिका मेटाउन मिल्दैन।',
|
||||
'platform_roles_fixed' => 'प्लेटफर्ममा केवल सुपर एडमिन र एजेन्ट भूमिका छन्; नयाँ भूमिका थप्न मिल्दैन।',
|
||||
'role_super_admin_permissions_fixed' => 'सुपर एडमिनसँग सबै अनुमति हुन्छ; क्याटलग परिवर्तनपछि lottery:admin-auth-sync चलाउनुहोस्।',
|
||||
|
||||
@@ -19,6 +19,8 @@ return [
|
||||
'player_create_capability_forbidden' => '当前代理账号未开通「创建玩家」能力,请联系上级代理调整权限。',
|
||||
'player_already_registered' => '该主站玩家已在彩票平台注册。',
|
||||
'player_wallet_balance_blocks_delete' => '该玩家钱包仍有余额,请先清空后再删除。',
|
||||
'player_credit_in_use_blocks_delete' => '该玩家仍有已占用信用额度,请先结清或释放后再删除。',
|
||||
'player_unpaid_settlement_blocks_delete' => '该玩家仍有未结账单,请先结清或核销后再删除。',
|
||||
'player_has_tickets_blocks_delete' => '该玩家存在注单记录,无法删除。',
|
||||
'role_cannot_delete_super_admin' => '不能删除超级管理员角色。',
|
||||
'platform_roles_fixed' => '平台仅保留「超级管理员」与「代理」两个内置角色,不支持新增。',
|
||||
|
||||
@@ -28,7 +28,9 @@ test('audit log presenter maps business action and entity target', function ():
|
||||
|
||||
$payload = AuditLogApiPresenter::row($row);
|
||||
|
||||
expect($payload['module_label'])->toBe('代理')
|
||||
expect($payload['operator_label'])->toBe('管理员 #1')
|
||||
->and($payload['operator_subtitle'])->toBeNull()
|
||||
->and($payload['module_label'])->toBe('代理')
|
||||
->and($payload['action_label'])->toBe('同步代理角色权限')
|
||||
->and($payload['target_label'])->toBe('角色 #5');
|
||||
});
|
||||
@@ -106,18 +108,9 @@ test('agent role permission sync records one business audit and skips middleware
|
||||
});
|
||||
|
||||
test('audit log index returns chinese display labels', function (): void {
|
||||
AuditLogger::record(
|
||||
AuditLogger::OPERATOR_ADMIN,
|
||||
1,
|
||||
'agent',
|
||||
'agent_role.sync_permissions',
|
||||
'admin_role',
|
||||
'9',
|
||||
);
|
||||
|
||||
$admin = AdminUser::query()->create([
|
||||
'username' => 'audit_list_super',
|
||||
'name' => 'Super',
|
||||
'name' => '超管甲',
|
||||
'email' => null,
|
||||
'password' => Hash::make('secret-strong'),
|
||||
'status' => 0,
|
||||
@@ -125,10 +118,21 @@ test('audit log index returns chinese display labels', function (): void {
|
||||
grantSuperAdminRole($admin);
|
||||
$token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;
|
||||
|
||||
AuditLogger::record(
|
||||
AuditLogger::OPERATOR_ADMIN,
|
||||
(int) $admin->id,
|
||||
'agent',
|
||||
'agent_role.sync_permissions',
|
||||
'admin_role',
|
||||
'9',
|
||||
);
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||
->getJson('/api/v1/admin/audit-logs?per_page=5')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', ErrorCode::Success->value)
|
||||
->assertJsonPath('data.items.0.operator_label', '超管甲')
|
||||
->assertJsonPath('data.items.0.operator_subtitle', '管理员 #'.$admin->id)
|
||||
->assertJsonPath('data.items.0.module_label', '代理')
|
||||
->assertJsonPath('data.items.0.action_label', '同步代理角色权限')
|
||||
->assertJsonPath('data.items.0.target_label', '角色 #9');
|
||||
|
||||
@@ -165,3 +165,28 @@ test('enabling currency as bettable bootstraps odds items and jackpot pool', fun
|
||||
'currency_code' => 'USD',
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot delete currency referenced by admin site default currency', function (): void {
|
||||
$token = mintCurrencyAdminToken();
|
||||
|
||||
Currency::query()->create([
|
||||
'code' => 'EUR',
|
||||
'name' => 'Euro',
|
||||
'decimal_places' => 2,
|
||||
'is_enabled' => true,
|
||||
'is_bettable' => false,
|
||||
]);
|
||||
|
||||
DB::table('admin_sites')
|
||||
->where('is_default', true)
|
||||
->update(['currency_code' => 'EUR']);
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||
->deleteJson('/api/v1/admin/currencies/EUR')
|
||||
->assertStatus(422)
|
||||
->assertJsonPath('data.references.0', '站点默认币种');
|
||||
|
||||
$this->assertDatabaseHas('currencies', [
|
||||
'code' => 'EUR',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -390,7 +390,7 @@ test('manual burst broadcast includes published first prize number', function ()
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||
->postJson('/api/v1/admin/jackpot/pools/'.$pool->id.'/manual-burst', [
|
||||
'draw_id' => $draw->id,
|
||||
'draw_id' => (string) $draw->draw_no,
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
|
||||
@@ -170,3 +170,171 @@ test('period close aggregates share ledger written by game settlement recorder',
|
||||
->and((int) $playerBill->gross_win_loss)->toBe($betMinor)
|
||||
->and((int) $playerBill->rebate_amount)->toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('credit settlement records base rebate plus add-on rebate and keeps extra rebate separate', function (): void {
|
||||
$siteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
|
||||
$siteCode = (string) DB::table('admin_sites')->where('id', $siteId)->value('code');
|
||||
$rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');
|
||||
|
||||
$super = \App\Models\AdminUser::query()->create([
|
||||
'username' => 'pipe_extra_super',
|
||||
'name' => 'Super',
|
||||
'email' => null,
|
||||
'password' => \Illuminate\Support\Facades\Hash::make('secret-strong'),
|
||||
'status' => 0,
|
||||
]);
|
||||
grantSuperAdminRole($super);
|
||||
|
||||
$leaf = app(AgentNodeService::class)->createChild($super, agentChildPayload([
|
||||
'parent_id' => $rootId,
|
||||
'code' => 'PIPE-X',
|
||||
'name' => 'Pipe X',
|
||||
'username' => 'pipe_x',
|
||||
'total_share_rate' => 25,
|
||||
'credit_limit' => 100_000,
|
||||
'default_player_rebate' => 0.005,
|
||||
'can_grant_extra_rebate' => true,
|
||||
]));
|
||||
|
||||
AgentProfile::query()->where('agent_node_id', $rootId)->update([
|
||||
'total_share_rate' => 100,
|
||||
'default_player_rebate' => 0.005,
|
||||
]);
|
||||
|
||||
$player = Player::query()->create([
|
||||
'site_code' => $siteCode,
|
||||
'agent_node_id' => $leaf->id,
|
||||
'site_player_id' => 'pipe-x1',
|
||||
'username' => 'pipeextra',
|
||||
'nickname' => null,
|
||||
'auth_source' => 'lottery_native',
|
||||
'funding_mode' => 'credit',
|
||||
'default_currency' => 'NPR',
|
||||
'status' => 0,
|
||||
]);
|
||||
|
||||
DB::table('player_credit_accounts')->insert([
|
||||
'player_id' => $player->id,
|
||||
'credit_limit' => 50_000,
|
||||
'used_credit' => 0,
|
||||
'frozen_credit' => 0,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
DB::table('player_rebate_profiles')->insert([
|
||||
'player_id' => $player->id,
|
||||
'game_type' => 'big',
|
||||
'rebate_rate' => 0.005,
|
||||
'extra_rebate_rate' => 0.002,
|
||||
'inherit_from_agent' => false,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$betMinor = 10_000;
|
||||
$draw = Draw::query()->create([
|
||||
'draw_no' => 'PIPE-DRAW-X',
|
||||
'business_date' => now()->toDateString(),
|
||||
'sequence_no' => 108,
|
||||
'status' => DrawStatus::Open->value,
|
||||
'current_result_version' => 0,
|
||||
'settle_version' => 0,
|
||||
'is_reopened' => false,
|
||||
]);
|
||||
|
||||
$order = TicketOrder::query()->create([
|
||||
'order_no' => 'ORD-PIPE-X',
|
||||
'player_id' => $player->id,
|
||||
'draw_id' => $draw->id,
|
||||
'currency_code' => 'NPR',
|
||||
'total_bet_amount' => $betMinor,
|
||||
'total_rebate_amount' => 0,
|
||||
'total_actual_deduct' => $betMinor,
|
||||
'total_estimated_payout' => 0,
|
||||
'status' => 'confirmed',
|
||||
'submit_source' => 'h5',
|
||||
'client_trace_id' => 'pipe-trace-x',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$item = TicketItem::query()->create([
|
||||
'ticket_no' => 'T-PIPE-X',
|
||||
'order_id' => $order->id,
|
||||
'player_id' => $player->id,
|
||||
'draw_id' => $draw->id,
|
||||
'original_number' => '1234',
|
||||
'normalized_number' => '1234',
|
||||
'play_code' => 'big',
|
||||
'dimension' => 2,
|
||||
'digit_slot' => null,
|
||||
'bet_mode' => 'single',
|
||||
'unit_bet_amount' => $betMinor,
|
||||
'total_bet_amount' => $betMinor,
|
||||
'rebate_rate_snapshot' => '0.0000',
|
||||
'commission_rate_snapshot' => '0.0000',
|
||||
'actual_deduct_amount' => $betMinor,
|
||||
'odds_snapshot_json' => [
|
||||
['prize_scope' => 'first', 'rebate_rate' => '0.0100', 'commission_rate' => '0.0000', 'odds_value' => 250000],
|
||||
],
|
||||
'rule_snapshot_json' => [
|
||||
'base_rebate_rate' => '0.0100',
|
||||
'player_addon_rebate_rate' => '0.0070',
|
||||
'rebate_inherited_from_agent' => false,
|
||||
],
|
||||
'combination_count' => 1,
|
||||
'estimated_max_payout' => 0,
|
||||
'risk_locked_amount' => 0,
|
||||
'status' => 'settled_lose',
|
||||
'win_amount' => 0,
|
||||
'jackpot_win_amount' => 0,
|
||||
]);
|
||||
$item->setRelation('player', $player);
|
||||
|
||||
app(AgentGameSettlementRecorder::class)->recordForTicketItem($item, 0, 'settled_lose');
|
||||
|
||||
$item->refresh();
|
||||
expect((float) $item->agent_rebate_rate_snapshot)->toBe(0.015);
|
||||
|
||||
$basic = DB::table('rebate_records')
|
||||
->where('ticket_item_id', $item->id)
|
||||
->where('rebate_type', 'basic')
|
||||
->first();
|
||||
$extra = DB::table('rebate_records')
|
||||
->where('ticket_item_id', $item->id)
|
||||
->where('rebate_type', 'extra')
|
||||
->first();
|
||||
|
||||
expect($basic)->not->toBeNull()
|
||||
->and((float) $basic->rebate_rate)->toBe(0.015)
|
||||
->and((int) $basic->rebate_amount)->toBe(150);
|
||||
expect($extra)->not->toBeNull()
|
||||
->and((float) $extra->rebate_rate)->toBe(0.002)
|
||||
->and((int) $extra->rebate_amount)->toBe(20);
|
||||
|
||||
$ledger = DB::table('share_ledger')->where('ticket_item_id', $item->id)->first();
|
||||
expect($ledger)->not->toBeNull()
|
||||
->and((int) $ledger->basic_rebate)->toBe(150);
|
||||
|
||||
$settledAt = (string) $ledger->settled_at;
|
||||
$periodId = (int) DB::table('settlement_periods')->insertGetId([
|
||||
'admin_site_id' => $siteId,
|
||||
'period_start' => now()->parse($settledAt)->subDay(),
|
||||
'period_end' => now()->parse($settledAt)->addDay(),
|
||||
'status' => 'open',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
app(AgentSettlementPeriodCloseService::class)->closePeriod($periodId);
|
||||
|
||||
$playerBill = DB::table('settlement_bills')
|
||||
->where('settlement_period_id', $periodId)
|
||||
->where('bill_type', 'player')
|
||||
->where('owner_id', $player->id)
|
||||
->first();
|
||||
|
||||
expect($playerBill)->not->toBeNull()
|
||||
->and((int) $playerBill->rebate_amount)->toBe(170);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\AdminUser;
|
||||
use App\Models\TicketItem;
|
||||
use App\Lottery\DrawStatus;
|
||||
use App\Models\JackpotPool;
|
||||
use App\Models\OddsVersion;
|
||||
use App\Models\TicketOrder;
|
||||
use App\Models\PlayerWallet;
|
||||
use App\Models\DrawResultItem;
|
||||
@@ -17,6 +18,7 @@ use App\Events\JackpotBurstBroadcast;
|
||||
use App\Services\Draw\DrawResultViewService;
|
||||
use App\Models\JackpotContribution;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Lottery\ConfigVersionStatus;
|
||||
use Database\Seeders\CurrencySeeder;
|
||||
use Database\Seeders\PlayTypeSeeder;
|
||||
use App\Lottery\DrawResultBatchStatus;
|
||||
@@ -292,6 +294,62 @@ test('jackpot contribution respects switch and minimum bet threshold', function
|
||||
expect(JackpotContribution::query()->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('jackpot contribution uses total bet amount instead of actual deduct amount', function (): void {
|
||||
jackpotUpsertPool([
|
||||
'currency_code' => 'NPR',
|
||||
'current_amount' => 0,
|
||||
'contribution_rate' => '0.1000',
|
||||
'trigger_threshold' => 1,
|
||||
'payout_rate' => '1.0000',
|
||||
'force_trigger_draw_gap' => 0,
|
||||
'min_bet_amount' => 10_000,
|
||||
'status' => 1,
|
||||
'last_trigger_draw_id' => null,
|
||||
]);
|
||||
|
||||
$player = jackpotTestPlayer('jprebate');
|
||||
$draw = jackpotOpenDraw('20260511-902A');
|
||||
|
||||
$oddsVersionId = OddsVersion::query()
|
||||
->where('status', ConfigVersionStatus::Active->value)
|
||||
->value('id');
|
||||
expect($oddsVersionId)->not->toBeNull();
|
||||
|
||||
DB::table('odds_items')
|
||||
->where('version_id', $oddsVersionId)
|
||||
->where('play_code', 'straight')
|
||||
->update(['rebate_rate' => 0.01]);
|
||||
|
||||
DB::table('player_rebate_profiles')->insert([
|
||||
'player_id' => $player->id,
|
||||
'game_type' => 'straight',
|
||||
'rebate_rate' => 0.005,
|
||||
'extra_rebate_rate' => 0.002,
|
||||
'inherit_from_agent' => false,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
|
||||
->postJson('/api/v1/ticket/place', [
|
||||
'draw_id' => '20260511-902A',
|
||||
'currency_code' => 'NPR',
|
||||
'client_trace_id' => 'jp-rebate-base',
|
||||
'lines' => [['number' => '1234', 'play_code' => 'straight', 'amount' => 10_000]],
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.summary.total_actual_deduct', 9_830);
|
||||
|
||||
$contribution = JackpotContribution::query()->firstOrFail();
|
||||
$item = TicketItem::query()->firstOrFail();
|
||||
$pool = JackpotPool::query()->where('currency_code', 'NPR')->firstOrFail();
|
||||
|
||||
expect((int) $item->total_bet_amount)->toBe(10_000)
|
||||
->and((int) $item->actual_deduct_amount)->toBe(9_830)
|
||||
->and((int) $contribution->contribution_amount)->toBe(1_000)
|
||||
->and((int) $pool->current_amount)->toBe(1_000);
|
||||
});
|
||||
|
||||
test('jackpot bursts by configured play combination trigger before threshold', function (): void {
|
||||
Event::fake([JackpotBurstBroadcast::class]);
|
||||
config([
|
||||
|
||||
@@ -18,22 +18,10 @@ test('public settings requires allowed group', function (): void {
|
||||
$this->getJson('/api/v1/settings?group=wallet')
|
||||
->assertStatus(400)
|
||||
->assertJsonPath('code', ErrorCode::ClientHttpError->value);
|
||||
});
|
||||
|
||||
test('public settings returns currency group', function (): void {
|
||||
\App\Models\LotterySetting::query()->updateOrCreate(
|
||||
['setting_key' => 'currency.display_decimals'],
|
||||
[
|
||||
'group_name' => 'currency',
|
||||
'value_json' => 3,
|
||||
'description_zh' => '展示小数位',
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
$this->getJson('/api/v1/settings?group=currency')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', ErrorCode::Success->value)
|
||||
->assertJsonFragment(['key' => 'currency.display_decimals', 'value' => 3]);
|
||||
->assertStatus(400)
|
||||
->assertJsonPath('code', ErrorCode::ClientHttpError->value);
|
||||
});
|
||||
|
||||
test('public settings returns frontend group only', function (): void {
|
||||
|
||||
@@ -910,6 +910,70 @@ test('ticket place sold out for second player after first consumes shared pool',
|
||||
expect((int) $pool->remaining_amount)->toBe(2000);
|
||||
});
|
||||
|
||||
test('ticket preview and place apply base rebate plus player add-on rebate for wallet player', function (): void {
|
||||
$player = ticketPlayerWithWallet(500_000);
|
||||
ticketOpenDraw();
|
||||
|
||||
$oddsVersionId = OddsVersion::query()
|
||||
->where('status', ConfigVersionStatus::Active->value)
|
||||
->value('id');
|
||||
expect($oddsVersionId)->not->toBeNull();
|
||||
|
||||
DB::table('odds_items')
|
||||
->where('version_id', $oddsVersionId)
|
||||
->where('play_code', 'big')
|
||||
->update(['rebate_rate' => 0.01]);
|
||||
|
||||
DB::table('player_rebate_profiles')->insert([
|
||||
'player_id' => $player->id,
|
||||
'game_type' => 'big',
|
||||
'rebate_rate' => 0.005,
|
||||
'extra_rebate_rate' => 0.002,
|
||||
'inherit_from_agent' => false,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'draw_id' => '20260511-001',
|
||||
'currency_code' => 'NPR',
|
||||
'client_trace_id' => 'trace-wallet-rebate-stack',
|
||||
'lines' => [
|
||||
['number' => '1234', 'play_code' => 'big', 'amount' => 10_000],
|
||||
],
|
||||
];
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
|
||||
->postJson('/api/v1/ticket/preview', $payload)
|
||||
->assertOk()
|
||||
->assertJsonPath('data.summary.total_bet_amount', 10_000)
|
||||
->assertJsonPath('data.summary.total_actual_deduct', 9_830)
|
||||
->assertJsonPath('data.summary.total_rebate_amount', 170)
|
||||
->assertJsonPath('data.lines.0.rebate_rate', '0.0170')
|
||||
->assertJsonPath('data.lines.0.rebate_amount', 170)
|
||||
->assertJsonPath('data.lines.0.actual_deduct_amount', 9_830)
|
||||
->assertJsonPath('data.lines.0.rule_snapshot_json.base_rebate_rate', '0.0100')
|
||||
->assertJsonPath('data.lines.0.rule_snapshot_json.player_addon_rebate_rate', '0.0070')
|
||||
->assertJsonPath('data.lines.0.rule_snapshot_json.rebate_inherited_from_agent', false);
|
||||
|
||||
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
|
||||
->postJson('/api/v1/ticket/place', $payload)
|
||||
->assertOk()
|
||||
->assertJsonPath('data.summary.total_bet_amount', 10_000)
|
||||
->assertJsonPath('data.summary.total_actual_deduct', 9_830);
|
||||
|
||||
$item = TicketItem::query()->where('play_code', 'big')->firstOrFail();
|
||||
$ruleSnapshot = is_array($item->rule_snapshot_json) ? $item->rule_snapshot_json : [];
|
||||
|
||||
expect((string) $item->rebate_rate_snapshot)->toBe('0.0170')
|
||||
->and((int) $item->actual_deduct_amount)->toBe(9_830)
|
||||
->and($ruleSnapshot['base_rebate_rate'] ?? null)->toBe('0.0100')
|
||||
->and($ruleSnapshot['player_addon_rebate_rate'] ?? null)->toBe('0.0070');
|
||||
|
||||
$wallet = PlayerWallet::query()->where('player_id', $player->id)->firstOrFail();
|
||||
expect((int) $wallet->balance)->toBe(500_000 - 9_830);
|
||||
});
|
||||
|
||||
test('ticket pending confirmation reconcile releases risk when wallet deduction is missing', function (): void {
|
||||
$draw = ticketOpenDraw();
|
||||
$player = ticketPlayerWithWallet();
|
||||
|
||||
Reference in New Issue
Block a user