144 lines
12 KiB
PHP
144 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use App\Services\FundingDossierPreparation;
|
|
use App\Services\FundingProgrammeReferences;
|
|
use App\Services\FundingProgrammes;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Str;
|
|
use Tests\TestCase;
|
|
|
|
final class FinancialInstitutionsSourceTest extends TestCase
|
|
{
|
|
use DatabaseTransactions;
|
|
|
|
public function test_assisted_editor_prepares_without_publishing_and_preserves_deliberate_edits(): void
|
|
{
|
|
$this->withoutVite();
|
|
$actor = User::factory()->create();
|
|
config(['portal.managers' => [$actor->email]]);
|
|
$this->actingAs($actor);
|
|
$this->get('/management/fundos/referencias-assistidas')->assertOk()->assertInertia(fn ($page) => $page->component('funding/assisted')->has('batch.items', 275));
|
|
$plan = $this->getJson('/management/fundos/referencias/arko')->assertOk()->json();
|
|
$receipt = $this->postJson('/management/fundos/referencias/arko/preparar', ['hash' => $plan['hash']])->assertOk()->assertJsonPath('created', true)->assertJsonPath('matches_reference', true)->json();
|
|
$id = $receipt['id'];
|
|
$this->assertNull(DB::table('funding_programmes')->where('id', $id)->value('published_version_id'));
|
|
$this->postJson('/management/fundos/referencias/arko/preparar', ['hash' => $plan['hash']])->assertOk()->assertJsonPath('created', false)->assertJsonPath('id', $id);
|
|
$body = [...$receipt['publication'], 'reason' => 'SYNTHETIC explicit editorial publication confirmation, rolled back.'];
|
|
$this->postJson('/management/fundos/'.$id.'/publicar', $body)->assertUnprocessable();
|
|
$published = $this->postJson('/management/fundos/'.$id.'/publicar', [...$body, 'confirm' => true])->assertOk()->json('version_id');
|
|
$this->postJson('/management/fundos/'.$id.'/publicar', [...$body, 'confirm' => true])->assertOk()->assertJsonPath('version_id', $published);
|
|
$row = DB::table('funding_programmes')->where('id', $id)->first();
|
|
$draft = json_decode($row->draft, true);
|
|
$draft['summary'] .= ' Deliberate QA editorial clarification.';
|
|
DB::table('funding_programmes')->where('id', $id)->update(['draft' => json_encode($draft), 'version' => $row->version + 1]);
|
|
$this->postJson('/management/fundos/referencias/arko/preparar', ['hash' => $plan['hash']])->assertOk()->assertJsonPath('matches_reference', false)->assertJsonPath('publication', null);
|
|
$this->assertSame($draft, json_decode(DB::table('funding_programmes')->where('id', $id)->value('draft'), true));
|
|
$other = User::factory()->create();
|
|
$this->actingAs($other)->get('/management/fundos/referencias-assistidas')->assertForbidden();
|
|
}
|
|
|
|
public function test_city_or_branch_text_is_searchable_without_treating_wildcards_as_search_commands(): void
|
|
{
|
|
$this->withoutVite();
|
|
Http::preventStrayRequests();
|
|
config(['investor-path.enabled' => true, 'suitecrm.enabled' => false]);
|
|
$actor = User::factory()->create();
|
|
config(['portal.managers' => [$actor->email]]);
|
|
$this->actingAs($actor);
|
|
$references = app(FundingProgrammeReferences::class);
|
|
$plan = $references->preview($actor, 'arko');
|
|
$id = $references->prepare($actor, 'arko', $plan['hash'])['id'];
|
|
$service = app(FundingProgrammes::class);
|
|
$publication = $service->preview($actor, $id);
|
|
$service->publish($actor, $id, ['version' => $publication['version'], 'hash' => $publication['hash'], 'confirm' => true, 'reason' => 'SYNTHETIC QA city search through the existing controller, rolled back.']);
|
|
$province = DB::table('geo_locations')->where('location_type', 'province')->where('name', 'Sofala')->value('id');
|
|
$filters = ['q' => 'Beira', 'territory' => $province, 'location_mode' => 'physical', 'category' => 'insurance', 'institution_type' => 'insurer'];
|
|
$this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($page) => $page->component('funding/index')->where('items.data.0.id', $id));
|
|
$this->get('/fundos?'.http_build_query([...$filters, 'q' => '%']))->assertOk()->assertInertia(fn ($page) => $page->component('funding/index')->has('items.data', 0));
|
|
$record = $service->published($id);
|
|
$location = collect($record['payload']['locations'])->first(fn ($loc) => $loc['territory_id'] === $province && $loc['role'] === 'branch');
|
|
$case = $this->postJson('/investimentos', ['title' => 'SYNTHETIC continuity during investor preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
|
|
$tracking = app(FundingDossierPreparation::class);
|
|
$context = $tracking->context($actor, $case, null);
|
|
$saved = $this->postJson('/fundos/'.$id.'/dossier', ['context' => $case, 'version' => $context['version'], 'version_id' => $record['version_id'], 'location_id' => $location['id'], 'location_mode' => 'physical', 'territory' => $province, 'need' => 'insurance', 'operation_key' => (string) Str::uuid(), 'consent' => true])->assertOk()->json();
|
|
$this->post('/investimentos/'.$case.'/aplicabilidade', ['version' => $saved['version'], 'land_needed' => 'unknown', 'external_funding' => 'yes', 'viability' => 'unknown', 'reason' => 'SYNTHETIC next preparation step retains selected insurer and provenance.'])->assertRedirect();
|
|
$continued = $tracking->context($actor, $case, null);
|
|
$this->assertSame($saved['selections'], $continued['selections']);
|
|
$this->assertGreaterThan($saved['version'], $continued['version']);
|
|
$this->assertSame('insurance', $continued['selections'][0]['need']);
|
|
Http::assertNothingSent();
|
|
}
|
|
|
|
public function test_supplied_institutions_can_be_found_by_physical_location_category_and_type_and_remain_traceable_in_one_dossier(): void
|
|
{
|
|
$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);
|
|
$this->withoutVite();
|
|
Http::preventStrayRequests();
|
|
config(['investor-path.enabled' => true, 'suitecrm.enabled' => false]);
|
|
$actor = User::factory()->create();
|
|
config(['portal.managers' => [$actor->email]]);
|
|
$this->actingAs($actor);
|
|
$source = json_decode(file_get_contents(database_path('data/funding-institutions-nov2026.json')), true, 512, JSON_THROW_ON_ERROR);
|
|
$references = app(FundingProgrammeReferences::class);
|
|
$catalogue = app(FundingProgrammes::class);
|
|
$records = [];
|
|
foreach ($source['references'] as $code => $reference) {
|
|
$plan = $references->preview($actor, $code);
|
|
$id = $references->prepare($actor, $code, $plan['hash'])['id'];
|
|
$this->assertNull(DB::table('funding_programmes')->where('id', $id)->value('published_version_id'), $code);
|
|
$ready = $catalogue->preview($actor, $id);
|
|
$catalogue->publish($actor, $id, ['version' => $ready['version'], 'hash' => $ready['hash'], 'confirm' => true, 'reason' => 'SYNTHETIC QA publication of supplied documentary facts; rolled back.']);
|
|
$records[$code] = $catalogue->published($id);
|
|
$this->assertSame($reference['draft']['institution_key'], $records[$code]['payload']['institution_key']);
|
|
}
|
|
$this->assertCount(270, $records);
|
|
$this->assertCount(270, array_unique(array_map(fn ($r) => $r['payload']['institution_key'], $records)));
|
|
$province = DB::table('geo_locations')->where('location_type', 'province')->where('name', 'Nampula')->value('id');
|
|
$filters = ['territory' => $province, 'location_mode' => 'physical', 'category' => 'insurance', 'institution_type' => 'insurer', 'certainty' => 'documented'];
|
|
$found = $catalogue->catalogueQuery($filters)->pluck('p.code')->all();
|
|
$this->assertContains('arko', $found);
|
|
$this->assertNotContains('bci', $found);
|
|
$this->assertNotContains('issm', $found);
|
|
$this->assertFalse($catalogue->catalogueQuery(['territory' => $province, 'need' => 'investment'])->where('p.id', $records['arko']['id'])->exists(), 'Insurer is not silently a credit provider');
|
|
$this->assertCount(8, $catalogue->catalogueQuery(['institution_type' => 'pension_manager'])->get());
|
|
$this->assertFalse($catalogue->catalogueQuery([])->where('p.id', $records['abc-historical']['id'])->exists());
|
|
$this->assertTrue($catalogue->catalogueQuery(['include_historical' => true])->where('p.id', $records['abc-historical']['id'])->exists());
|
|
$this->assertSame('access-bank', $records['abc-historical']['payload']['successor_key']);
|
|
$this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($p) => $p->component('funding/index')->where('filters.category', 'insurance')->where('filters.institution_type', 'insurer'));
|
|
$case = $this->postJson('/investimentos', ['title' => 'SYNTHETIC bank and insurance preparation', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id');
|
|
$tracking = app(FundingDossierPreparation::class);
|
|
$before = $tracking->context($actor, $case, null);
|
|
$bank = ['context' => $case, 'version' => $before['version'], 'version_id' => $records['bci']['version_id'], 'need' => 'investment', 'territory' => $province, 'product' => 'bci-oferta', 'operation_key' => (string) Str::uuid(), 'consent' => true];
|
|
$afterBank = $this->postJson('/fundos/'.$records['bci']['id'].'/dossier', $bank)->assertOk()->json();
|
|
$location = collect($records['arko']['payload']['locations'])->first(fn ($loc) => $loc['territory_id'] === $province && $loc['role'] === 'branch');
|
|
$this->assertNotNull($location);
|
|
$insurance = ['context' => $case, 'version' => $afterBank['version'], 'version_id' => $records['arko']['version_id'], 'need' => 'insurance', 'territory' => $province, 'location_mode' => 'physical', 'location_id' => $location['id'], 'operation_key' => (string) Str::uuid(), 'consent' => true];
|
|
$saved = $this->postJson('/fundos/'.$records['arko']['id'].'/dossier', $insurance)->assertOk()->assertJsonCount(2, 'selections')->json();
|
|
$this->postJson('/fundos/'.$records['arko']['id'].'/dossier', $insurance)->assertOk()->assertJsonCount(2, 'selections');
|
|
$this->postJson('/fundos/'.$records['arko']['id'].'/dossier', [...$insurance, 'version' => $saved['version'], 'operation_key' => (string) Str::uuid(), 'location_id' => 'foreign-location'])->assertUnprocessable();
|
|
$catalogue->withdraw($actor, $records['arko']['id'], $records['arko']['version'], 'SYNTHETIC QA withdrawal without rewriting investor history.');
|
|
$recovered = $tracking->context($actor, $case, null);
|
|
$this->assertSame($saved['selections'], $recovered['selections']);
|
|
$chosen = $recovered['selections'][1];
|
|
$this->assertSame('arko', $chosen['institution_key']);
|
|
$this->assertSame(['insurance'], $chosen['categories']);
|
|
$this->assertContains('insurer', $chosen['institution_types']);
|
|
$this->assertSame($location['id'], $chosen['location']['id']);
|
|
$this->assertSame($source['source']['sha256'], $chosen['location']['source_document_sha256']);
|
|
$this->getJson('/investimentos/'.$case)->assertOk()->assertJsonCount(2, 'funding_selections');
|
|
$directory = base_path('outputs/funding-directory-20261110/institutions');
|
|
if (! is_dir($directory)) {
|
|
mkdir($directory, 0700, true);
|
|
}
|
|
file_put_contents($directory.'/content.json', json_encode(['synthetic_editorial_publication_rolled_back' => true, 'source' => $source['source'], 'records' => $records, 'nampula_insurers' => $found, 'dossier_recovered' => $recovered, 'no_external_submission' => true], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
|
|
Http::assertNothingSent();
|
|
}
|
|
}
|