c975e16a14
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
3.1 KiB
PHP
76 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Support\RussianRegions;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* Одноразовый бэкфилл: проставляет deals.city (имя субъекта) у уже существующих сделок,
|
|
* у которых city ещё пуст, по resolved_subject_code связанного лида
|
|
* (deals → supplier_lead_deliveries → supplier_leads). Идемпотентно (только city IS NULL).
|
|
*
|
|
* Запускается через .github/workflows/artisan-run.yml (mutating-whitelist, confirm_apply).
|
|
* Парная правка для RouteSupplierLeadJob, который заполняет city у новых сделок.
|
|
*/
|
|
final class DealsBackfillRegionCityCommand extends Command
|
|
{
|
|
protected $signature = 'deals:backfill-region-city {--dry-run : Только посчитать, ничего не записывать}';
|
|
|
|
protected $description = 'Дозаполнить deals.city именем региона по resolved_subject_code лида (одноразовый бэкфилл)';
|
|
|
|
public function handle(): int
|
|
{
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
// BYPASSRLS-роль: бэкфилл идёт по всем тенантам без SET app.current_tenant_id.
|
|
$conn = DB::connection('pgsql_supplier');
|
|
$map = RussianRegions::CODE_TO_NAME;
|
|
|
|
$rows = $conn->table('deals')
|
|
->join('supplier_lead_deliveries as dlv', 'dlv.deal_id', '=', 'deals.id')
|
|
->join('supplier_leads as sl', 'sl.id', '=', 'dlv.supplier_lead_id')
|
|
->whereNull('deals.city')
|
|
->whereNotNull('sl.resolved_subject_code')
|
|
->select('deals.id', 'deals.received_at', 'sl.resolved_subject_code')
|
|
->get();
|
|
|
|
$seen = [];
|
|
$updated = 0;
|
|
foreach ($rows as $r) {
|
|
$dealId = (int) $r->id;
|
|
if (isset($seen[$dealId])) {
|
|
continue; // у сделки несколько доставок — обрабатываем один раз
|
|
}
|
|
$seen[$dealId] = true;
|
|
|
|
$name = $map[(int) $r->resolved_subject_code] ?? null;
|
|
if ($name === null) {
|
|
continue; // код вне справочника 1..89 — пропускаем
|
|
}
|
|
|
|
if (! $dryRun) {
|
|
$conn->table('deals')
|
|
->where('id', $dealId)
|
|
->where('received_at', $r->received_at) // partition key
|
|
->whereNull('city') // идемпотентный страж
|
|
->update(['city' => $name]);
|
|
}
|
|
$updated++;
|
|
}
|
|
|
|
$prefix = $dryRun ? '[dry-run] ' : '';
|
|
$this->info("{$prefix}deals.city backfill: {$updated} обновлено из ".count($seen).' кандидатов.');
|
|
Log::info('deals.backfill_region_city', [
|
|
'updated' => $updated,
|
|
'candidates' => count($seen),
|
|
'dry_run' => $dryRun,
|
|
]);
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|