feat: 新增赔率版本和玩法配置版本的删除接口,支持删除草稿版本

This commit is contained in:
2026-05-15 15:30:40 +08:00
parent 5398af0a55
commit c0cd8be0fb
18 changed files with 574 additions and 125 deletions

View File

@@ -0,0 +1,140 @@
<?php
namespace Database\Seeders;
use App\Models\Currency;
use App\Models\OddsItem;
use App\Models\PlayType;
use App\Models\OddsVersion;
use App\Models\PlayConfigItem;
use Illuminate\Database\Seeder;
use App\Models\PlayConfigVersion;
use Illuminate\Support\Facades\DB;
use App\Support\OddsStandardScopes;
use App\Lottery\ConfigVersionStatus;
/**
* 将「玩法目录」与已存在的玩法配置 / 赔率版本对齐(幂等,可反复执行)。
*
* 典型场景:`play_types` 已扩展,但某条 active/draft `play_config_items` `odds_items`
* 仍是早期子集,后台出现大量「无配置行」或赔率缺档。
*
* 执行php artisan db:seed --class=PlayOperationalAlignmentSeeder
*/
final class PlayOperationalAlignmentSeeder extends Seeder
{
private const MIN_BET = 100;
private const MAX_BET = 500_000_000;
public function run(): void
{
$this->call(PlayTypeSeeder::class);
DB::transaction(function (): void {
$open = [ConfigVersionStatus::Active->value, ConfigVersionStatus::Draft->value];
foreach (PlayConfigVersion::query()->whereIn('status', $open)->orderBy('id')->cursor() as $version) {
$this->syncPlayConfigItems($version);
}
foreach (OddsVersion::query()->whereIn('status', $open)->orderBy('id')->cursor() as $version) {
$this->syncOddsItemsForAllPlayTypes($version);
}
});
}
private function syncPlayConfigItems(PlayConfigVersion $version): void
{
$vid = (int) $version->id;
$existing = PlayConfigItem::query()
->where('version_id', $vid)
->pluck('play_code')
->all();
$have = array_fill_keys($existing, true);
foreach (PlayType::query()->orderBy('sort_order')->orderBy('play_code')->cursor() as $pt) {
if (isset($have[$pt->play_code])) {
continue;
}
PlayConfigItem::query()->create([
'version_id' => $vid,
'play_code' => $pt->play_code,
'is_enabled' => (bool) $pt->is_enabled,
'min_bet_amount' => self::MIN_BET,
'max_bet_amount' => self::MAX_BET,
'display_order' => (int) $pt->sort_order,
'rule_text_zh' => null,
'rule_text_en' => null,
'rule_text_ne' => null,
'extra_config_json' => null,
]);
}
}
private function syncOddsItemsForAllPlayTypes(OddsVersion $version): void
{
$vid = (int) $version->id;
$currencies = OddsItem::query()
->where('version_id', $vid)
->distinct()
->pluck('currency_code')
->filter(static fn ($c) => is_string($c) && $c !== '')
->values();
if ($currencies->isEmpty()) {
$fallback = Currency::query()
->where('is_bettable', true)
->where('is_enabled', true)
->orderBy('code')
->value('code');
if ($fallback === null || $fallback === '') {
return;
}
$currencies = collect([strtoupper((string) $fallback)]);
}
foreach ($currencies as $currencyCode) {
$currencyCode = strtoupper((string) $currencyCode);
foreach (PlayType::query()->orderBy('sort_order')->orderBy('play_code')->cursor() as $pt) {
$playCode = $pt->play_code;
$anchor = OddsItem::query()
->where('version_id', $vid)
->where('play_code', $playCode)
->where('currency_code', $currencyCode)
->orderByDesc('id')
->first();
$rebate = (float) ($anchor?->rebate_rate ?? 0);
$commission = (float) ($anchor?->commission_rate ?? 0);
foreach (OddsStandardScopes::PRESET_ODDS_BY_SCOPE as $scope => $oddsValue) {
$exists = OddsItem::query()
->where('version_id', $vid)
->where('play_code', $playCode)
->where('currency_code', $currencyCode)
->where('prize_scope', $scope)
->exists();
if ($exists) {
continue;
}
OddsItem::query()->create([
'version_id' => $vid,
'play_code' => $playCode,
'prize_scope' => $scope,
'odds_value' => $oddsValue,
'rebate_rate' => $rebate,
'commission_rate' => $commission,
'currency_code' => $currencyCode,
'extra_config_json' => null,
]);
}
}
}
}
}