create(); $project = Project::factory()->create([ 'tenant_id' => $tenant->id, 'signal_type' => 'site', 'signal_identifier' => 'krasnoyarsk.carmoney.ru', ]); $subdomainSp = SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'krasnoyarsk.carmoney.ru', 'supplier_external_id' => 'ext-sub', 'current_limit' => 100, 'sync_status' => 'ok', ]); $rootSp = SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'carmoney.ru', 'supplier_external_id' => 'ext-root', 'current_limit' => 100, 'sync_status' => 'ok', ]); DB::connection('pgsql_supplier')->table('project_supplier_links')->insert([ 'project_id' => $project->id, 'supplier_project_id' => $subdomainSp->id, 'platform' => 'B2', 'subject_code' => null, ]); $exitCode = Artisan::call('supplier:backfill-root-links'); expect($exitCode)->toBe(0); expect( DB::connection('pgsql_supplier')->table('project_supplier_links') ->where('project_id', $project->id) ->where('supplier_project_id', $rootSp->id) ->exists() )->toBeTrue(); }); it('backfill: idempotent — повторный прогон ничего не добавляет', function () { $tenant = Tenant::factory()->create(); $project = Project::factory()->create([ 'tenant_id' => $tenant->id, 'signal_type' => 'site', 'signal_identifier' => 'client.carmoney.ru', ]); $subSp = SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'client.carmoney.ru', 'supplier_external_id' => 'ext1', 'current_limit' => 100, 'sync_status' => 'ok', ]); SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'carmoney.ru', 'supplier_external_id' => 'ext2', 'current_limit' => 100, 'sync_status' => 'ok', ]); DB::connection('pgsql_supplier')->table('project_supplier_links')->insert([ 'project_id' => $project->id, 'supplier_project_id' => $subSp->id, 'platform' => 'B2', 'subject_code' => null, ]); Artisan::call('supplier:backfill-root-links'); $afterFirst = DB::connection('pgsql_supplier')->table('project_supplier_links') ->where('project_id', $project->id)->count(); Artisan::call('supplier:backfill-root-links'); $afterSecond = DB::connection('pgsql_supplier')->table('project_supplier_links') ->where('project_id', $project->id)->count(); expect($afterFirst)->toBe(2); expect($afterSecond)->toBe(2); }); it('backfill --dry-run: ничего не пишет в БД', function () { $tenant = Tenant::factory()->create(); $project = Project::factory()->create([ 'tenant_id' => $tenant->id, 'signal_type' => 'site', 'signal_identifier' => 'next.vashinvestor.ru', ]); $subSp = SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'next.vashinvestor.ru', 'supplier_external_id' => 'extn1', 'current_limit' => 100, 'sync_status' => 'ok', ]); SupplierProject::create([ 'platform' => 'B2', 'signal_type' => 'site', 'unique_key' => 'vashinvestor.ru', 'supplier_external_id' => 'extn2', 'current_limit' => 100, 'sync_status' => 'ok', ]); DB::connection('pgsql_supplier')->table('project_supplier_links')->insert([ 'project_id' => $project->id, 'supplier_project_id' => $subSp->id, 'platform' => 'B2', 'subject_code' => null, ]); Artisan::call('supplier:backfill-root-links', ['--dry-run' => true]); $count = DB::connection('pgsql_supplier')->table('project_supplier_links') ->where('project_id', $project->id)->count(); expect($count)->toBe(1); });