withoutVite(); $db = DB::selectOne('select current_database() as name, inet_server_port() as port'); $this->assertSame('simulator_fiscal_delta_20261021_test', $db->name); $this->assertSame(55441, (int) $db->port); config(['investor-path.enabled' => true, 'suitecrm.enabled' => false, 'investmoz_ai.enabled' => false]); } private function dossier(User $user, string $title): string { return $this->actingAs($user)->postJson('/investimentos', ['title' => $title, 'client_key' => (string) Str::uuid(), 'reuse_consent' => true])->assertCreated()->json('id'); } public function test_same_dossier_context_reuses_linked_draft_and_preserves_account_and_project_boundaries(): void { $owner = User::factory()->create(); $a = $this->dossier($owner, 'A'); $b = $this->dossier($owner, 'B'); foreach ([[$a, 'MZN', 'national'], [$b, 'USD', 'foreign']] as [$id,$currency,$origin]) { $this->actingAs($owner)->postJson('/api/v1/simulation-drafts', ['context' => $id, 'personal_snapshot' => ['investor_origin' => $origin, 'tax_residency_country' => 'ZA', 'person_type' => 'collective'], 'economic_snapshot' => ['purpose' => 'simulate_only', 'project_title' => $id, 'currency' => $currency, 'expected_start_date' => '2026-01-01']], ['Idempotency-Key' => (string) Str::uuid()])->assertCreated(); $v = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk(); $v->assertJsonPath('prefill.simulator.currency', $currency)->assertJsonPath('prefill.simulator.investor_origin', $origin)->assertJsonPath('prefill.simulator.tax_residency_country', 'ZA'); $this->assertSame('linked_simulation', $v->json('context.provenance.currency.kind')); } $this->actingAs(User::factory()->create())->getJson('/investimentos/'.$a.'/contexto')->assertForbidden(); $this->actingAs($owner)->getJson('/investimentos/'.$a.'/contexto')->assertOk()->assertJsonPath('prefill.simulator.currency', 'MZN'); } public function test_context_change_is_previewed_versioned_and_idempotent_without_changing_the_source_draft(): void { $owner = User::factory()->create(); $id = $this->dossier($owner, 'Impacto'); $view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json(); $body = ['version' => $view['case']['version'], 'selection' => [], 'declarations' => ['currency' => 'USD', 'investor_origin' => 'foreign', 'tax_residency_country' => 'MZ'], 'replace_fields' => []]; $plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $body)->assertOk()->json(); $this->assertNotEmpty($plan['updated']); $this->assertTrue($plan['dependency_changed']); $control = [...$body, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true]; $this->postJson('/investimentos/'.$id.'/contexto/confirmar', $control)->assertOk(); $this->postJson('/investimentos/'.$id.'/contexto/confirmar', $control)->assertOk()->assertJsonPath('replayed', true); $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->assertJsonPath('prefill.simulator.currency', 'USD')->assertJsonPath('prefill.simulator.tax_residency_country', 'MZ'); } public function test_zone_selection_reuses_existing_reference_and_impact_workflow_without_granting_a_benefit(): void { $owner = User::factory()->create(); $id = $this->dossier($owner, 'Zonas QA'); $template = app(InvestmentZones::class)->visible()->where('category', 'industrial_park')->firstOrFail(); foreach (['zee', 'zfi', 'industrial_park'] as $category) { // Synthetic catalogue metadata, rolled back. Never a legal source or published rule in homologation. $zone = $template->replicate(); $zone->id = (string) Str::uuid(); $zone->code = 'SINT-CONTEXT-'.Str::random(12); $zone->name = 'SINTÉTICO QA '.$category; $zone->category = $category; $zone->legal_regime = $category === 'industrial_park' ? 'pending' : $category; $zone->source_evidence = [['source_type' => 'government', 'url' => 'https://example.test/synthetic-zone', 'supports' => 'Synthetic test only; no legal or eligibility conclusion']]; $zone->save(); $view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json(); $body = ['version' => $view['case']['version'], 'selection' => ['park' => 'park:'.$zone->id]]; $plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $body)->assertOk()->json(); $this->assertSame($category, $plan['fields']['investment_regime']); $this->assertContains('S17', $plan['review_steps']); $this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$body, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk(); $after = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk(); $after->assertJsonPath('prefill.simulator.investment_regime', $category); $snapshot = json_decode($after->json('prefill.simulator.context_applicability_snapshot'), true); $this->assertSame($zone->id, $snapshot['zone']['id']); $this->assertArrayNotHasKey('benefit_rate', $snapshot); } $view = $this->getJson('/investimentos/'.$id.'/contexto')->json(); $body = ['version' => $view['case']['version'], 'selection' => ['park' => null]]; $plan = $this->postJson('/investimentos/'.$id.'/contexto/previa', $body)->assertOk()->json(); $this->postJson('/investimentos/'.$id.'/contexto/confirmar', [...$body, 'preview_hash' => $plan['preview_hash'], 'operation_key' => (string) Str::uuid(), 'confirm' => true])->assertOk(); $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->assertJsonPath('prefill.simulator.investment_regime', 'general')->assertJsonPath('prefill.simulator.special_zone_id', ''); } public function test_a_title_edit_does_not_invalidate_applicability_or_ask_for_irrelevant_reviews(): void { $owner = User::factory()->create(); $id = $this->dossier($owner, 'Título original'); $view = $this->getJson('/investimentos/'.$id.'/contexto')->assertOk()->json(); $this->postJson('/investimentos/'.$id.'/contexto/previa', ['version' => $view['case']['version'], 'selection' => [], 'declarations' => ['project_title' => 'Título revisto']]) ->assertOk()->assertJsonPath('dependency_changed', false)->assertJsonPath('review_steps', []); } }