310 lines
23 KiB
PHP
310 lines
23 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\EconomicCluster;
|
|
use App\Models\InvestmentDossier;
|
|
use App\Models\Opportunity;
|
|
use App\Models\Project;
|
|
use App\Models\Sector;
|
|
use App\Models\User;
|
|
use App\Services\InvestmentCatalogue;
|
|
use App\Services\InvestmentRelations;
|
|
use App\Services\InvestmentRelationshipRepair;
|
|
use App\Services\InvestmentTerritorialValidation;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
use Tests\TestCase;
|
|
|
|
class InvestmentRelationshipTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function fixture(): array
|
|
{
|
|
$parent = null;
|
|
$ids = [];
|
|
foreach (['country', 'province', 'district', 'admin_post', 'locality', 'site'] as $type) {
|
|
$id = (string) Str::uuid();
|
|
DB::table('geo_locations')->insert(['id' => $id, 'code' => $id, 'name' => 'QA '.$type, 'location_type' => $type, 'parent_id' => $parent,
|
|
'data_classification' => 'public', 'source_system' => 'cartografia-workbook', 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$id]);
|
|
$ids[$type] = $id;
|
|
$parent = $id;
|
|
}
|
|
$project = Project::factory()->create(['code' => 'A99', 'name' => 'QA Anchor', 'status' => 'draft', 'data_classification' => 'internal']);
|
|
DB::table('geo_locations')->where('id', $ids['site'])->update(['source_system' => 'QA documented site', 'external_id' => null]);
|
|
$dossier = InvestmentDossier::create(['project_id' => $project->id, 'title' => 'QA Anchor dossier', 'source' => 'QA synthetic dossier source',
|
|
'content' => ['location' => 'QA province, district and site', 'description' => 'Unique documented component needle'], 'publication_status' => 'published', 'published_at' => now()->subMinute(), 'approval_basis' => 'document_owner', 'approval_evidence' => 'Synthetic QA fixture disclosure only']);
|
|
$cluster = EconomicCluster::create(['code' => 'QA-CLU', 'name' => 'QA Cluster', 'sector' => 'QA', 'status' => 'planned']);
|
|
$clusterDossier = InvestmentDossier::create(['cluster_id' => $cluster->id, 'title' => 'QA Cluster dossier', 'source' => 'QA synthetic cluster source',
|
|
'content' => ['anchors' => 'A99; QA documented proposal'], 'publication_status' => 'published', 'published_at' => now()->subMinute(), 'approval_basis' => 'document_owner', 'approval_evidence' => 'Synthetic QA fixture disclosure only']);
|
|
DB::table('cluster_projects')->insert(['id' => (string) Str::uuid(), 'cluster_id' => $cluster->id, 'project_id' => $project->id, 'role' => 'anchor', 'source_system' => 'upgrade-v4']);
|
|
DB::table('project_locations')->insert(['id' => (string) Str::uuid(), 'project_id' => $project->id, 'geo_location_id' => $ids['site'], 'role' => 'primary', 'data_classification' => 'public']);
|
|
DB::table('geo_geometries')->insert(['id' => (string) Str::uuid(), 'geo_location_id' => $ids['site'], 'geometry_type' => 'point', 'data_classification' => 'public',
|
|
'geom' => DB::raw('ST_SetSRID(ST_MakePoint(32.5,-25.9),4326)'), 'source_system' => 'QA documented coordinates fixture']);
|
|
$sector = Sector::create(['name' => 'QA sector', 'slug' => 'qa-sector', 'is_active' => true]);
|
|
$opportunity = Opportunity::create(['sector_id' => $sector->id, 'reference' => 'QA-REL', 'title' => 'QA opportunity', 'slug' => 'qa-rel', 'status' => 'published', 'published_at' => now()->subMinute()]);
|
|
DB::table('opportunity_projects')->insert(['opportunity_id' => $opportunity->id, 'project_id' => $project->id]);
|
|
|
|
return compact('ids', 'project', 'dossier', 'cluster', 'clusterDossier', 'opportunity', 'sector');
|
|
}
|
|
|
|
public function test_project_location_and_dossier_navigation_are_bidirectional_without_changing_project_status(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$this->get('/carteira/'.$f['dossier']->id)->assertInertia(fn (Assert $p) => $p->has('geography.locations', 1)->has('geography.locations.0.path', 4)
|
|
->where('geography.locations.0.role', 'primary')->where('geography.locations.0.coordinates.0.geometry.coordinates.0', 32.5)->has('opportunities', 1)->has('geography.clusters', 1));
|
|
$this->get('/oportunidades/qa-rel?from_dossier='.$f['dossier']->id)->assertInertia(fn (Assert $p) => $p->where('dossierOrigin.id', $f['dossier']->id)
|
|
->where('context.projects.0.dossiers.0.id', $f['dossier']->id)->has('context.projects.0.geography.locations', 1));
|
|
$this->get('/oportunidades/qa-rel?from_dossier='.$f['clusterDossier']->id)->assertNotFound();
|
|
$this->assertSame('draft', $f['project']->fresh()->status);
|
|
}
|
|
|
|
public function test_search_and_all_territorial_levels_follow_explicit_project_relations(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$filters = [];
|
|
foreach (['province', 'district', 'admin_post', 'locality'] as $type) {
|
|
$filters[$type.'_id'] = $f['ids'][$type];
|
|
$this->assertSame([$f['opportunity']->id], app(InvestmentCatalogue::class)->query($filters)->pluck('id')->all());
|
|
$this->get('/carteira?'.http_build_query($filters))->assertInertia(fn (Assert $p) => $p->has('records.data', 2));
|
|
}
|
|
$this->assertSame([$f['opportunity']->id], app(InvestmentCatalogue::class)->query(['q' => 'component needle'])->pluck('id')->all());
|
|
$this->assertSame([$f['opportunity']->id], app(InvestmentCatalogue::class)->query(['geo_location_id' => $f['ids']['province']])->pluck('id')->all());
|
|
$map = app(InvestmentCatalogue::class)->map($filters);
|
|
$this->assertSame(1, $map['georeferenced_count']);
|
|
$this->assertSame('linked_project_site', $map['features'][0]['properties']['location_basis']);
|
|
}
|
|
|
|
public function test_cluster_member_locations_do_not_create_opportunity_project_relations_or_a_cluster_point(): void
|
|
{
|
|
$f = $this->fixture();
|
|
DB::table('opportunity_projects')->delete();
|
|
DB::table('opportunity_clusters')->insert(['opportunity_id' => $f['opportunity']->id, 'cluster_id' => $f['cluster']->id]);
|
|
$this->get('/carteira/'.$f['clusterDossier']->id)->assertInertia(fn (Assert $p) => $p->has('geography.locations', 0)
|
|
->has('geography.members', 1)->where('geography.members.0.validation_status', 'pending')->has('geography.members.0.locations', 1)->has('opportunities', 1));
|
|
$this->get('/carteira/'.$f['dossier']->id.'?from='.$f['clusterDossier']->id)->assertOk();
|
|
$this->assertSame([$f['opportunity']->id], app(InvestmentCatalogue::class)->query(['province_id' => $f['ids']['province']])->pluck('id')->all());
|
|
$this->assertSame([], app(InvestmentCatalogue::class)->context($f['opportunity']->id)['projects']->all());
|
|
$this->assertSame(0, app(InvestmentCatalogue::class)->map([])['georeferenced_count']);
|
|
$this->assertDatabaseCount('opportunity_projects', 0);
|
|
}
|
|
|
|
public function test_private_revoked_and_deleted_relationships_are_not_disclosed(): void
|
|
{
|
|
$f = $this->fixture();
|
|
DB::table('project_locations')->update(['data_classification' => 'confidential']);
|
|
DB::table('cluster_projects')->update(['validation_status' => 'revoked']);
|
|
$this->assertSame([], app(InvestmentRelations::class)->projectLocations($f['project']->id));
|
|
$this->assertSame(0, app(InvestmentRelations::class)->memberships()->count());
|
|
$this->assertSame(0, app(InvestmentCatalogue::class)->map([])['georeferenced_count']);
|
|
$f['dossier']->update(['publication_status' => 'draft']);
|
|
$this->get('/carteira/'.$f['dossier']->id)->assertNotFound();
|
|
}
|
|
|
|
public function test_multiple_documented_sites_are_shown_separately_without_choosing_one(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$id = (string) Str::uuid();
|
|
DB::table('geo_locations')->insert(['id' => $id, 'code' => $id, 'name' => 'QA second site', 'location_type' => 'site', 'parent_id' => $f['ids']['locality'], 'data_classification' => 'public']);
|
|
DB::table('project_locations')->insert(['id' => (string) Str::uuid(), 'project_id' => $f['project']->id, 'geo_location_id' => $id, 'role' => 'secondary', 'data_classification' => 'public']);
|
|
DB::table('geo_geometries')->insert(['id' => (string) Str::uuid(), 'geo_location_id' => $id, 'geometry_type' => 'point', 'data_classification' => 'public', 'geom' => DB::raw('ST_SetSRID(ST_MakePoint(32.6,-25.8),4326)')]);
|
|
$map = app(InvestmentCatalogue::class)->map([]);
|
|
$this->assertSame(1, $map['georeferenced_count']);
|
|
$this->assertCount(0, $map['unlocated']);
|
|
$this->assertCount(2, $map['features']);
|
|
$this->assertSame(2, $map['marker_count']);
|
|
$this->assertCount(2, app(InvestmentRelations::class)->projectLocations($f['project']->id));
|
|
}
|
|
|
|
public function test_direct_context_impact_and_missing_geography_remain_distinct(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$catalogue = app(InvestmentCatalogue::class);
|
|
$this->assertEmpty($catalogue->context($f['opportunity']->id)['opportunity_locations']);
|
|
$this->assertSame([$f['opportunity']->id], $catalogue->query(['territory_basis' => 'context'])->pluck('id')->all());
|
|
$this->assertSame([], $catalogue->query(['territory_basis' => 'direct'])->pluck('id')->all());
|
|
DB::table('opportunity_locations')->insert(['opportunity_id' => $f['opportunity']->id, 'geo_location_id' => $f['ids']['district']]);
|
|
$location = $catalogue->context($f['opportunity']->id)['opportunity_locations'][0];
|
|
$this->assertSame('opportunity', $location['role']);
|
|
$this->assertSame([$f['opportunity']->id], $catalogue->query(['q' => 'QA district'])->pluck('id')->all());
|
|
$this->assertNull($location['source_reference']);
|
|
$this->assertEmpty($location['coordinates']);
|
|
$this->assertSame([], $catalogue->query(['territory_basis' => 'context'])->pluck('id')->all());
|
|
$this->assertSame([$f['opportunity']->id], $catalogue->query(['territory_basis' => 'direct', 'geo_location_id' => $f['ids']['district']])->pluck('id')->all());
|
|
$this->assertSame([], $catalogue->query(['territory_basis' => 'direct', 'geo_location_id' => $f['ids']['site']])->pluck('id')->all());
|
|
DB::table('project_locations')->update(['role' => 'impact']);
|
|
$this->assertSame('impact', $catalogue->context($f['opportunity']->id)['projects'][0]->geography['locations'][0]['role']);
|
|
$this->assertSame(0, $catalogue->map([])['georeferenced_count']);
|
|
DB::table('opportunity_locations')->delete();
|
|
DB::table('opportunity_projects')->delete();
|
|
$this->assertEmpty($catalogue->context($f['opportunity']->id)['opportunity_locations']);
|
|
$this->assertSame(1, $catalogue->query([])->count());
|
|
$this->assertCount(1, $catalogue->map([])['unlocated']);
|
|
}
|
|
|
|
public function test_invalid_coordinates_are_rejected_and_polygon_provenance_is_preserved(): void
|
|
{
|
|
$f = $this->fixture();
|
|
DB::table('opportunity_locations')->insert(['opportunity_id' => $f['opportunity']->id, 'geo_location_id' => $f['ids']['site']]);
|
|
DB::table('geo_geometries')->insert(['id' => (string) Str::uuid(), 'geo_location_id' => $f['ids']['site'], 'geometry_type' => 'polygon', 'data_classification' => 'public',
|
|
'geom' => DB::raw("ST_GeomFromText('POLYGON((32 -26,33 -26,33 -25,32 -25,32 -26))',4326)"), 'source_system' => 'QA boundary', 'properties' => json_encode(['source_date' => '2026-10-08'])]);
|
|
$context = app(InvestmentCatalogue::class)->context($f['opportunity']->id);
|
|
$this->assertSame('2026-10-08', $context['opportunity_locations'][0]['boundaries'][0]['source_date']);
|
|
$this->assertSame('opportunity_site', app(InvestmentCatalogue::class)->map([])['features'][0]['properties']['location_basis']);
|
|
$this->assertCount(1, app(InvestmentCatalogue::class)->map([])['areas']);
|
|
try {
|
|
DB::transaction(fn () => DB::table('geo_geometries')->where('geo_location_id', $f['ids']['site'])->where('geometry_type', 'point')->update(['geom' => DB::raw('ST_SetSRID(ST_MakePoint(32.7,95),4326)')]));
|
|
$this->fail('Invalid coordinates must be rejected by the existing database guard.');
|
|
} catch (QueryException $error) {
|
|
$this->assertSame('23514', $error->getCode());
|
|
}
|
|
$this->assertSame(1, app(InvestmentCatalogue::class)->map([])['georeferenced_count']);
|
|
$this->assertCount(1, app(InvestmentCatalogue::class)->context($f['opportunity']->id)['opportunity_locations'][0]['coordinates']);
|
|
}
|
|
|
|
public function test_repair_requires_authenticated_management_is_transactional_and_replays_without_duplicates(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$directory = storage_path('framework/testing/relationship-repair-'.Str::uuid());
|
|
mkdir($directory, 0700, true);
|
|
config(['investment.repair_directory' => $directory]);
|
|
$dump = $directory.'/synthetic-qa-backup.dump';
|
|
file_put_contents($dump, 'synthetic isolated QA proof fixture');
|
|
$target = ['database' => DB::connection()->getDatabaseName(), 'port' => 55441];
|
|
file_put_contents($directory.'/backup-proof.json', json_encode(['restore_verified' => true, 'dump_path' => $dump, 'sha256' => hash_file('sha256', $dump), 'target' => $target]));
|
|
$row = ['project_id' => $f['project']->id, 'code' => 'A99', 'dossier_id' => $f['dossier']->id, 'dossier_version' => 1, 'geo_location_id' => $f['ids']['province'],
|
|
'role' => 'secondary', 'source_reference' => $f['dossier']->source, 'source_quote' => $f['dossier']->content['location'], 'reason' => 'QA documented province',
|
|
'expected_project_version' => $f['project']->fresh()->version_no, 'data_classification' => 'public'];
|
|
file_put_contents($directory.'/preview.json', json_encode(['target' => $target, 'locations' => [$row], 'memberships' => [], 'prepared_opportunities' => [], 'pending' => []]));
|
|
$hash = hash_file('sha256', $directory.'/preview.json');
|
|
$this->get('/management/relationship-repair')->assertRedirect('/login');
|
|
$manager = User::factory()->create();
|
|
$this->actingAs($manager)->get('/management/relationship-repair')->assertForbidden();
|
|
config(['portal.managers' => [$manager->email]]);
|
|
$this->get('/management/relationship-repair')->assertOk();
|
|
$this->postJson('/management/relationship-repair', ['hash' => str_repeat('0', 64)])->assertConflict();
|
|
$invalid = [...$row, 'expected_project_version' => $row['expected_project_version'] + 7, 'role' => 'impact'];
|
|
file_put_contents($directory.'/preview.json', json_encode(['target' => $target, 'locations' => [$row, $invalid], 'memberships' => []]));
|
|
$this->postJson('/management/relationship-repair', ['hash' => hash_file('sha256', $directory.'/preview.json')])->assertConflict();
|
|
$this->assertDatabaseCount('project_locations', 1);
|
|
file_put_contents($directory.'/preview.json', json_encode(['target' => $target, 'locations' => [$row], 'memberships' => [], 'prepared_opportunities' => [], 'pending' => []]));
|
|
$hash = hash_file('sha256', $directory.'/preview.json');
|
|
$this->postJson('/management/relationship-repair', ['hash' => $hash])->assertOk()->assertJsonPath('locations_created', 1);
|
|
$this->postJson('/management/relationship-repair', ['hash' => $hash])->assertOk()->assertJsonPath('replayed', true);
|
|
$this->assertDatabaseCount('project_locations', 2);
|
|
$this->assertSame('draft', $f['project']->fresh()->status);
|
|
$this->assertSame('published', $f['dossier']->fresh()->publication_status);
|
|
$changed = [...$row, 'role' => 'impact'];
|
|
file_put_contents($directory.'/preview.json', json_encode(['target' => $target, 'locations' => [$changed], 'memberships' => []]));
|
|
$this->postJson('/management/relationship-repair', ['hash' => hash_file('sha256', $directory.'/preview.json')])->assertConflict();
|
|
$this->assertDatabaseCount('project_locations', 2);
|
|
@unlink($directory.'/preview.json');
|
|
@unlink($directory.'/backup-proof.json');
|
|
@unlink($dump);
|
|
@rmdir($directory);
|
|
}
|
|
|
|
private function repairPlan(array $rows): array
|
|
{
|
|
$directory = storage_path('framework/testing/territorial-repair-'.Str::uuid());
|
|
mkdir($directory, 0700, true);
|
|
config(['investment.repair_directory' => $directory]);
|
|
$dump = $directory.'/qa.dump';
|
|
file_put_contents($dump, 'Synthetic QA fixture; not an active backup');
|
|
$target = ['database' => DB::connection()->getDatabaseName(), 'port' => 55441];
|
|
file_put_contents($directory.'/backup-proof.json', json_encode(['restore_verified' => true, 'dump_path' => $dump, 'sha256' => hash_file('sha256', $dump), 'target' => $target]));
|
|
file_put_contents($directory.'/preview.json', json_encode(['target' => $target, 'locations' => $rows, 'memberships' => [], 'pending' => [], 'prepared_opportunities' => []]));
|
|
$user = User::factory()->create();
|
|
config(['portal.managers' => [$user->email]]);
|
|
$this->actingAs($user);
|
|
|
|
return app(InvestmentRelationshipRepair::class)->preview();
|
|
}
|
|
|
|
private function territorialRow(array $f, string $level = 'province', string $role = 'secondary'): array
|
|
{
|
|
return ['project_id' => $f['project']->id, 'code' => 'A99', 'dossier_id' => $f['dossier']->id, 'dossier_version' => 1,
|
|
'geo_location_id' => $f['ids'][$level], 'role' => $role, 'source_reference' => $f['dossier']->source,
|
|
'source_quote' => $f['dossier']->content['location'], 'reason' => 'Explicit synthetic QA document',
|
|
'expected_project_version' => $f['project']->fresh()->version_no, 'data_classification' => 'public'];
|
|
}
|
|
|
|
public function test_individual_territories_without_coordinates_apply_sequentially_and_audit_actor_date_and_source(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$preview = $this->repairPlan([$this->territorialRow($f), $this->territorialRow($f, 'district', 'impact')]);
|
|
$this->assertSame('grounded', $preview['territorial'][0]['status']);
|
|
$this->assertCount(0, $preview['territorial'][0]['coordinates']);
|
|
$this->assertCount(1, $preview['territorial'][0]['current']);
|
|
$this->get('/management/relationship-repair')->assertInertia(fn (Assert $p) => $p->where('territorial.0.status', 'grounded')->where('territorial.1.proposed.role', 'impact'));
|
|
foreach ([0, 1] as $index) {
|
|
$fresh = app(InvestmentRelationshipRepair::class)->preview();
|
|
$request = ['hash' => $fresh['hash'], 'row_id' => $fresh['territorial'][$index]['row_id'], 'validation_hash' => $fresh['territorial'][$index]['validation_hash']];
|
|
$this->postJson('/management/relationship-repair', $request)->assertOk()->assertJsonPath('locations_created', 1);
|
|
$this->postJson('/management/relationship-repair', $request)->assertOk()->assertJsonPath('replayed', true);
|
|
}
|
|
$this->assertDatabaseCount('project_locations', 3);
|
|
$history = app(InvestmentRelationshipRepair::class)->preview()['history'];
|
|
$this->assertCount(2, $history);
|
|
$this->assertSame(auth()->id(), $history[0]['actor_id']);
|
|
$this->assertNotEmpty($history[0]['date']);
|
|
$this->assertSame($f['dossier']->source, $history[0]['data']['sources'][0]['source_reference']);
|
|
$this->assertSame('draft', $f['project']->fresh()->status);
|
|
}
|
|
|
|
public function test_pending_and_contradictory_rows_are_retained_while_grounded_rows_apply(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$good = $this->territorialRow($f);
|
|
$pending = [...$this->territorialRow($f, 'district'), 'source_quote' => ''];
|
|
$bad = [...$this->territorialRow($f, 'locality', 'impact'), 'province_id' => (string) Str::uuid()];
|
|
$preview = $this->repairPlan([$good, $pending, $bad]);
|
|
$this->assertSame(['grounded', 'pending', 'contradictory'], array_column($preview['territorial'], 'status'));
|
|
foreach ([1, 2] as $index) {
|
|
$this->postJson('/management/relationship-repair', ['hash' => $preview['hash'], 'row_id' => $preview['territorial'][$index]['row_id'], 'validation_hash' => $preview['territorial'][$index]['validation_hash']])->assertConflict();
|
|
}
|
|
$this->postJson('/management/relationship-repair', ['hash' => $preview['hash']])->assertOk()->assertJsonPath('locations_created', 1);
|
|
$this->assertDatabaseCount('project_locations', 2);
|
|
$this->assertDatabaseMissing('project_locations', ['project_id' => $f['project']->id, 'geo_location_id' => $f['ids']['locality']]);
|
|
$this->assertSame('contradictory', app(InvestmentRelationshipRepair::class)->preview()['territorial'][2]['status']);
|
|
}
|
|
|
|
public function test_coordinate_inclusion_and_broken_hierarchy_are_checked_without_inventing_boundaries(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$row = $this->territorialRow($f, 'site');
|
|
$validator = app(InvestmentTerritorialValidation::class);
|
|
$without = $validator->validate($row);
|
|
$this->assertSame('grounded', $without['status']);
|
|
$this->assertSame([], $without['coordinate_checks']);
|
|
DB::table('geo_geometries')->insert(['id' => (string) Str::uuid(), 'geo_location_id' => $f['ids']['province'], 'geometry_type' => 'polygon', 'data_classification' => 'public',
|
|
'geom' => DB::raw('ST_MakeEnvelope(32,-26,33,-25,4326)'), 'source_system' => 'Synthetic QA boundary']);
|
|
$inside = $validator->validate($row);
|
|
$this->assertSame('grounded', $inside['status']);
|
|
$this->assertTrue($inside['coordinate_checks'][0]['compatible']);
|
|
DB::table('geo_geometries')->where('geo_location_id', $f['ids']['site'])->update(['geom' => DB::raw('ST_SetSRID(ST_MakePoint(35,-25.9),4326)')]);
|
|
$outside = $validator->validate($row);
|
|
$this->assertSame('contradictory', $outside['status']);
|
|
$this->assertFalse($outside['coordinate_checks'][0]['compatible']);
|
|
$this->assertSame('contradictory', $validator->validate([...$row, 'coordinates' => [181, -25]])['status']);
|
|
DB::table('geo_locations')->where('id', $f['ids']['admin_post'])->update(['deleted_at' => now()]);
|
|
$broken = $validator->validate($this->territorialRow($f, 'locality'));
|
|
$this->assertSame('contradictory', $broken['status']);
|
|
$this->assertStringContainsString('antepassado indisponível', implode(' ', $broken['issues']));
|
|
}
|
|
|
|
public function test_individual_application_rejects_changed_territorial_preview_and_unknown_row(): void
|
|
{
|
|
$f = $this->fixture();
|
|
$preview = $this->repairPlan([$this->territorialRow($f)]);
|
|
$this->postJson('/management/relationship-repair', ['hash' => $preview['hash'], 'row_id' => str_repeat('a', 64), 'validation_hash' => $preview['territorial'][0]['validation_hash']])->assertUnprocessable();
|
|
DB::table('geo_locations')->where('id', $f['ids']['province'])->update(['name' => 'Changed QA territory']);
|
|
$this->postJson('/management/relationship-repair', ['hash' => $preview['hash'], 'row_id' => $preview['territorial'][0]['row_id'], 'validation_hash' => $preview['territorial'][0]['validation_hash']])->assertConflict();
|
|
$this->assertDatabaseCount('project_locations', 1);
|
|
}
|
|
}
|