withoutVite(); $identity = DB::selectOne('select current_database() as name,inet_server_port() as port'); $this->assertSame('simulator_fiscal_delta_20261021_test', $identity->name); $this->assertSame(55441, (int) $identity->port); config(['investor-path.enabled' => true, 'suitecrm.enabled' => false]); Http::preventStrayRequests(); $this->editor = User::factory()->create(); config(['portal.managers' => [$this->editor->email]]); $this->actingAs($this->editor); } private function prepared(string $code): string { $references = app(FundingProgrammeReferences::class); $plan = $references->preview($this->editor, $code); return $references->prepare($this->editor, $code, $plan['hash'])['id']; } private function publish(string $id): array { $service = app(FundingProgrammes::class); $plan = $service->preview($this->editor, $id); $service->publish($this->editor, $id, ['version' => $plan['version'], 'hash' => $plan['hash'], 'confirm' => true, 'reason' => 'SYNTHETIC QA editorial publication; rolled back, not live content.']); return $service->published($id); } private function province(string $name): string { return DB::table('geo_locations')->where('location_type', 'province')->where('name', $name)->value('id'); } public function test_provided_content_is_queryable_with_sources_contacts_coverage_and_no_automatic_publication_or_duplicates(): void { $references = app(FundingProgrammeReferences::class); $service = app(FundingProgrammes::class); $before = $service->publicQuery()->count(); $codes = ['bci', 'millennium-bim', 'absa', 'standard-bank', 'moza', 'bni', 'gapi', 'fecop', 'semeia', 'fcid-viii', 'fae']; $records = []; foreach ($codes as $code) { $id = $this->prepared($code); $this->assertSame($id, $this->prepared($code)); $this->assertNull(DB::table('funding_programmes')->where('id', $id)->value('published_version_id')); $this->assertSame($before + count($records), $service->publicQuery()->count()); $records[$code] = $this->publish($id); $this->assertNotEmpty($records[$code]['payload']['source_url']); } $this->assertSame($before + 11, $service->publicQuery()->count()); $this->assertCount(2, $records['bni']['payload']['products']); $this->assertContains('Maputo Cidade', array_column($records['bni']['payload']['locations'][0]['territory_path'], 'name')); $this->assertSame('national', $records['bni']['payload']['products'][0]['coverage']); $this->assertCount(6, $records['fcid-viii']['payload']['territory_ids']); $this->assertSame('closed', $records['semeia']['payload']['windows'][0]['state']); $this->assertSame('unknown', $records['fae']['payload']['coverage']); $filters = ['territory' => $this->province('Cabo Delgado'), 'need' => 'investment']; $found = $service->catalogueQuery($filters)->pluck('p.code')->all(); $this->assertContains('bci', $found); $this->assertContains('bni', $found); $this->assertNotContains('fcid-viii', $found); $this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($p) => $p->component('funding/index')->where('filters.need', 'investment')); $this->get('/fundos/'.$records['bni']['id'])->assertOk()->assertInertia(fn ($p) => $p->component('funding/show')->where('record.payload.contacts.1.value', '+258 21 498 581')); file_put_contents(base_path('outputs/funding-directory-20261110/content-qa.json'), json_encode(['synthetic_editorial_publication_rolled_back' => true, 'provided_source_sha256' => '065203aacfae766c62cf9c2c272ebacc61ff23bd4ff9e91535939fede87f7617', 'records' => $records, 'cabo_delgado_investment_results' => $found], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)); Http::assertNothingSent(); } public function test_location_and_need_must_match_the_same_product_and_unknown_is_explicit(): void { $service = app(FundingProgrammes::class); $draft = app(FundingProgrammeReferences::class)->preview($this->editor, 'bci')['draft']; $draft['institution_key'] = 'synthetic-same-product'; $draft['title'] = 'SYNTHETIC QA — cross product scope'; $draft['products'][0]['coverage'] = 'territorial'; $draft['products'][0]['territory_ids'] = [$this->province('Maputo Província')]; $draft['products'][0]['needs'] = ['investment']; $other = $draft['products'][0]; $other['code'] = 'synthetic-working'; $other['needs'] = ['working_capital']; $other['territory_ids'] = [$this->province('Nampula')]; $draft['products'][] = $other; $id = $service->save($this->editor, null, ['version' => 0, 'code' => 'synthetic-cross', 'reason' => 'SYNTHETIC QA cross product coverage fixture.', 'draft' => $draft]); $this->publish($id); $base = ['territory' => $this->province('Nampula')]; $this->assertFalse($service->catalogueQuery([...$base, 'need' => 'investment'])->where('p.id', $id)->exists()); $this->assertTrue($service->catalogueQuery([...$base, 'need' => 'working_capital'])->where('p.id', $id)->exists()); $draft['products'][0]['coverage'] = 'unknown'; $draft['products'][0]['territory_ids'] = []; $draft['products'][0]['availability'] = 'unknown'; $service->save($this->editor, $id, ['version' => 1, 'code' => 'synthetic-cross', 'reason' => 'SYNTHETIC QA unknown coverage, not absence.', 'draft' => $draft]); $this->publish($id); $this->assertTrue($service->catalogueQuery([...$base, 'need' => 'investment'])->where('p.id', $id)->exists()); $this->assertFalse($service->catalogueQuery([...$base, 'need' => 'investment', 'certainty' => 'documented'])->where('p.id', $id)->exists()); $this->expectException(ValidationException::class); $service->save($this->editor, null, ['version' => 0, 'code' => 'synthetic-duplicate', 'reason' => 'SYNTHETIC QA duplicate stable institution guard.', 'draft' => $draft]); } public function test_selection_continues_in_existing_dossier_and_recovers_snapshot_without_sending_an_application(): void { $id = $this->prepared('bni'); $record = $this->publish($id); $caseId = $this->postJson('/investimentos', ['title' => 'SYNTHETIC QA funding preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id'); $context = app(FundingDossierPreparation::class)->context($this->editor, $caseId, null); $this->get('/fundos?'.http_build_query(['context' => $caseId, 'territory' => $this->province('Nampula'), 'need' => 'investment']))->assertOk()->assertInertia(fn ($page) => $page->component('funding/index')->where('items.data', fn ($rows) => collect($rows)->contains('id', $id))); $this->get('/fundos/'.$id.'?'.http_build_query(['context' => $caseId, 'territory' => $this->province('Nampula'), 'need' => 'investment']))->assertOk()->assertInertia(fn ($page) => $page->component('funding/show')->where('record.id', $id)->where('dossier.id', $caseId)->where('record.payload.contacts.1.value', '+258 21 498 581')); $body = ['context' => $caseId, 'version' => $context['version'], 'version_id' => $record['version_id'], 'product' => 'bni-oferta', 'need' => 'investment', 'territory' => $this->province('Nampula'), 'operation_key' => (string) Str::uuid(), 'consent' => true]; $saved = $this->postJson('/fundos/'.$id.'/dossier', $body)->assertOk()->json(); $this->assertCount(1, $saved['selections']); $this->assertSame($record['version_id'], $saved['selections'][0]['version_id']); $this->postJson('/fundos/'.$id.'/dossier', $body)->assertOk(); $this->postJson('/fundos/'.$id.'/dossier', [...$body, 'operation_key' => (string) Str::uuid()])->assertOk()->assertJsonCount(1, 'selections'); $this->postJson('/fundos/'.$id.'/dossier', [...$body, 'need' => 'equity'])->assertConflict(); $this->postJson('/fundos/'.$id.'/dossier', [...$body, 'opportunity' => 'opportunity:not-in-this-dossier', 'operation_key' => (string) Str::uuid()])->assertUnprocessable(); $this->assertSame(1, DB::table('desk_events')->where('case_id', $caseId)->where('action', 'funding_preparation_saved')->count()); $this->getJson('/investimentos/'.$caseId)->assertOk()->assertJsonCount(1, 'funding_selections'); $service = app(FundingProgrammes::class); $service->withdraw($this->editor, $id, $record['version'], 'SYNTHETIC QA withdrawal preserves consulted reference.'); $recovered = app(FundingDossierPreparation::class)->context($this->editor, $caseId, null); $this->assertSame($saved['selections'], $recovered['selections']); $this->actingAs(User::factory()->create())->postJson('/fundos/'.$id.'/dossier', $body)->assertForbidden(); $this->actingAs($this->editor); DB::table('desk_cases')->where('id', $caseId)->update(['closed_at' => now()]); $this->postJson('/fundos/'.$id.'/dossier', $body)->assertConflict(); $this->assertCount(1, app(FundingDossierPreparation::class)->context($this->editor, $caseId, null)['selections']); file_put_contents(base_path('outputs/funding-directory-20261110/dossier-qa.json'), json_encode(['synthetic' => true, 'recovered' => $recovered, 'one_native_event' => true, 'foreign_actor_refused' => true, 'closed_dossier_read_only' => true, 'no_external_submission' => true], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)); Http::assertNothingSent(); } }