Files
portal/app/database/seeders/OmegaDemoFieldSeeder.php
T
Дмитрий 4387333118 feat(Конкурентное поле): рабочее место конкуренты→источники→проекты (поверх автоподбора)
Фича «Конкурентное поле» на dev до уровня прототипа 2026-06-29-konkurentnoe-pole-proto.html.

Данные: box (proposal|field) на competitors+sources; phone_type city/mobile/tollfree рядом
с phone_kind (вариант C). 3 миграции, дефолты тарифов 300/50.

API (AutopodborController): GET /field (+счётчики), GET /proposals, PATCH/DELETE competitors
и sources с гвардами активного проекта, переключение box, POST /competitors/manual (+directory_urls),
competitor(id) обогащён box+project-статусом; projectStatus отдаёт limit/delivered/days/regions.
Смена источника проекта = PATCH /api/projects/{id} (реальный гвард слепка §14.10).

Фронт: FieldWorkspaceScreen/FieldCompetitorScreen/FieldProposalsScreen/FieldManualCompetitorScreen
+ field-shared.css (Forest) + AutopodborServicesPanel в Биллинге. Дословно по прототипу: подзаголовки,
баннер предложений, баннер правил времени 18:00 МСК, Справочник 2ГИС·Яндекс, статус проекта
5/день·заявки, окна сбора с ценами 300/50 + «что известно», полные формы. Пункт меню «Конкурентное поле».

Тесты: backend автоподбор 80/80, фронт автоподбор 49/49. Движок шага 2 = заглушка FakeCompetitorAgent.
OmegaDemoFieldSeeder — только для визуальной проверки (НЕ на прод).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 04:18:46 +03:00

171 lines
9.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Database\Seeders;
use App\Models\AutopodborCompetitor;
use App\Models\AutopodborRun;
use App\Models\AutopodborSource;
use App\Models\Project;
use App\Models\SystemSetting;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
/**
* ДЕМО-сид для визуальной проверки «Конкурентного поля» глазами клиента (Омега).
* НЕ для прода. Данные конкурентов — из реальных прогонов движка 28-29.06 (Красноярск,
* займы под залог авто). Создаёт демо-тенант + логин, включает фичу, наполняет поле и
* предложения реальными конкурентами и источниками (сайты + телефоны с типами).
*
* Запуск (только dev): php artisan db:seed --class=OmegaDemoFieldSeeder
* Логин: omega-demo@liderra.local / omega12345
*/
class OmegaDemoFieldSeeder extends Seeder
{
public function run(): void
{
// 1) Тенант «Омега (демо)» + пользователь с известным паролем
$tenant = Tenant::firstOrNew(['subdomain' => 'omega-demo']);
$tenant->organization_name = 'Омега (демо поля)';
$tenant->contact_email = 'omega-demo@liderra.local';
$tenant->status = 'active';
$tenant->balance_rub = '50000.00';
$tenant->delivered_in_month = 0;
$tenant->save();
$user = User::firstOrNew(['email' => 'omega-demo@liderra.local']);
$user->tenant_id = $tenant->id;
$user->first_name = 'Омега';
$user->last_name = 'Демо';
$user->password_hash = Hash::make('omega12345');
$user->email_verified_at = now();
$user->is_active = true;
$user->save();
// 2) Включить фичу + тарифы доп.услуг
SystemSetting::updateOrCreate(['key' => 'autopodbor_enabled'], ['value' => '1', 'type' => 'bool']);
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_search_rub'], ['value' => '300', 'type' => 'decimal']);
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_study_rub'], ['value' => '50', 'type' => 'decimal']);
DB::statement('SET app.current_tenant_id = '.$tenant->id);
// чистим прошлый демо-прогон (идемпотентность)
$oldRuns = AutopodborRun::where('tenant_id', $tenant->id)->pluck('id');
AutopodborSource::where('tenant_id', $tenant->id)->delete();
AutopodborCompetitor::where('tenant_id', $tenant->id)->delete();
AutopodborRun::whereIn('id', $oldRuns)->delete();
$run = AutopodborRun::create([
'tenant_id' => $tenant->id, 'kind' => 'search', 'status' => 'done',
'region_code' => 24, 'params' => ['region' => 'Красноярский край'],
]);
// 3) Реальные конкуренты Омеги (прогон 28-29.06). box=field — клиент отобрал в поле.
$gis = 'https://2gis.ru/krasnoyarsk/firm/0';
$ya = 'https://yandex.ru/maps/org/0';
$field = [
['КрасЛомбард', 'kraslombard24.ru', false, 95, 'Сеть ломбардов, займы под залог авто и техники', [$gis, $ya], [
['site', 'kraslombard24.ru', null, null],
['call', '73912771717', 'real', 'city'],
]],
['Голд Авто Инвест', 'goldautoinvest.ru', false, 90, 'Займы под залог автомобилей, Красноярск', [$gis, $ya], [
['site', 'goldautoinvest.ru', null, null],
['call', '73912000111', 'substitute', 'city'],
['call', '79130000222', 'real', 'mobile'],
]],
['Финео', 'fineo24.ru', true, 80, 'Федеральный сервис займов под ПТС', [$gis], [
['site', 'fineo24.ru', null, null],
['call', '78005000333', 'real', 'tollfree'],
]],
['Cashmotor', 'cashmotor.ru', true, 78, 'Федеральный автоломбард, залог авто', [], [
['site', 'cashmotor.ru', null, null],
]],
['Локо-Банк', 'lockobank.ru', true, 72, 'Автокредиты и займы под залог авто', [$ya], [
['site', 'lockobank.ru', null, null],
]],
];
// box=proposal — найдено движком, ещё не отобрано в поле
$proposals = [
['Автоломбард Экспресс', 'avtolombard-express.ru', false, 85, 'Срочные займы под залог авто, Красноярск'],
['Caranga', 'caranga.ru', true, 70, 'Федеральный автоломбanд'],
['Драйвзайм', 'drivezaim.ru', true, 65, 'Займы под залог ПТС онлайн'],
['Залог24', 'zalog24h.ru', true, 60, 'Круглосуточные займы под залог'],
['Кредди', 'creddy.ru', true, 55, 'Микрозаймы под залог авто'],
];
foreach ($field as $i => [$name, $site, $federal, $rel, $desc, $dirs, $srcs]) {
$comp = AutopodborCompetitor::create([
'tenant_id' => $tenant->id, 'search_run_id' => $run->id, 'study_run_id' => $run->id,
'studied_at' => now(), 'name' => $name, 'description' => $desc, 'is_federal' => $federal,
'relevance_pct' => $rel, 'origin' => 'auto', 'box' => 'field', 'site_url' => $site,
'directory_urls' => $dirs, 'dedup_key' => 'site:'.$site,
]);
foreach ($srcs as [$type, $ident, $kind, $ptype]) {
AutopodborSource::create([
'tenant_id' => $tenant->id, 'competitor_id' => $comp->id, 'study_run_id' => $run->id,
'signal_type' => $type, 'identifier' => $ident, 'phone_kind' => $kind, 'phone_type' => $ptype,
'box' => 'field', 'provenance_label' => $type === 'site' ? 'сайт компании' : 'карточка в 2ГИС',
'dedup_key' => $type.':'.$ident,
]);
}
}
foreach ($proposals as [$name, $site, $federal, $rel, $desc]) {
AutopodborCompetitor::create([
'tenant_id' => $tenant->id, 'search_run_id' => $run->id,
'name' => $name, 'description' => $desc, 'is_federal' => $federal,
'relevance_pct' => $rel, 'origin' => 'auto', 'box' => 'proposal', 'site_url' => $site,
'dedup_key' => 'site:'.$site,
]);
}
// 4) Демо-проекты: один «в работе», один «на паузе» — чтобы показать счётчики,
// паузу/возобновление и смену источника на живых данных. Минимальная строка
// (только обязательные поля), без джобов поставщика.
$linkProject = function (string $compName, bool $active) use ($tenant) {
$comp = AutopodborCompetitor::where('tenant_id', $tenant->id)->where('name', $compName)->first();
if (! $comp) {
return;
}
$src = AutopodborSource::where('competitor_id', $comp->id)->where('signal_type', 'site')->first();
if (! $src) {
return;
}
$p = Project::firstOrNew(['tenant_id' => $tenant->id, 'name' => $compName]);
$p->signal_identifier = $src->identifier;
$p->signal_type = 'site';
$p->signal_identifier = $src->identifier;
$p->is_active = $active;
$p->paused_at = $active ? null : now();
$p->daily_limit_target = 20;
$p->delivery_days_mask = 127;
$p->save();
$src->update(['created_project_id' => $p->id]);
};
$linkProject('КрасЛомбард', true); // в работе
$linkProject('Голд Авто Инвест', false); // на паузе
// источники-предложения у КрасЛомбарда (результат «собрать источники» — до переноса в работу)
$krl = AutopodborCompetitor::where('tenant_id', $tenant->id)->where('name', 'КрасЛомбард')->first();
if ($krl) {
foreach ([
['site', 'kraslombard-new.ru', null, null, '2ГИС — сайт в карточке компании'],
['call', '73912001100', 'real', 'city', '2ГИС — карточка компании'],
] as [$type, $ident, $kind, $ptype, $prov]) {
AutopodborSource::create([
'tenant_id' => $tenant->id, 'competitor_id' => $krl->id, 'study_run_id' => $run->id,
'signal_type' => $type, 'identifier' => $ident, 'phone_kind' => $kind, 'phone_type' => $ptype,
'box' => 'proposal', 'provenance_label' => $prov, 'dedup_key' => $type.':'.$ident.':sug',
]);
}
}
$this->command?->info('Омега-демо готова: '.count($field).' в поле (2 с проектами), '.count($proposals).' в предложениях. Логин omega-demo@liderra.local / omega12345');
}
}