assertSame('proactive_investment_20261027_test',$target->name); $this->assertSame(55441,(int)$target->port); $snapshot=static function(string $table): array { return collect(DB::select('select id::text as id,md5(row_to_json(t)::text) as hash from public."'.$table.'" t order by id'))->pluck('hash','id')->all(); }; $protected=[]; foreach(['opportunities','documents','opportunity_documents','simulation_form_drafts','users','organizations','audit_events']as$table)$protected[$table]=$snapshot($table); config(['investor-path.enabled'=>true,'suitecrm.enabled'=>false]); $this->actingAs(User::findOrFail(1021)); // Existing synthetic QA operator; no new grants. $base=json_decode(file_get_contents(base_path('tests/frontend/fixtures/irpc-assessment-preserved.json')),true,flags:JSON_THROW_ON_ERROR); $fixture=json_decode(file_get_contents(base_path('tests/frontend/fixtures/irpc-pec-preserved.json')),true,flags:JSON_THROW_ON_ERROR); $personal=['person_type'=>$base['person_type']];unset($base['person_type']); $id=null;$etag=null;$previous=null; foreach($fixture['cases']as$name=>$book){ $draft=$base;$store=json_decode($draft['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR); if($previous!==null)$book['history']=[$previous]; $store['irpcAnnual'][$draft['context_opportunity']]=$book; $draft['modelo_a_snapshot']=json_encode($store,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE); $payload=['personal_snapshot'=>$personal,'economic_snapshot'=>$draft]; if($id===null)$id=$this->postJson('/api/v1/simulation-drafts',$payload,['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id'); else $this->putJson('/api/v1/simulation-drafts/'.$id,$payload,['If-Match'=>$etag])->assertOk(); $response=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk();$etag=$response->headers->get('ETag');$back=$response->json('data.economic_snapshot'); $this->assertSame($draft['modelo_a_snapshot'],$back['modelo_a_snapshot']); $this->assertSame($draft['business_plan_snapshot'],$back['business_plan_snapshot']); $recovered=json_decode($back['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR); foreach(['irpcNormal','irpcWithholdings','books','currencyEvents','ispcQuarters']as$map)$this->assertSame($store[$map],$recovered[$map]); $saved=$recovered['irpcAnnual'][$draft['context_opportunity']];$m=$saved['result']['model']; $this->assertSame($book,$saved);$this->assertSame('IRPC-PEC/1',$m['pecDeduction']['version']); $this->assertFalse($m['officialBalancesConsumed']);$this->assertFalse($m['pecDeduction']['carryCreated']); $this->assertSame(['numerator'=>'1408','denominator'=>'1'],$m['assessment']['colecta']); if($name==='missing'){$this->assertSame('indeterminate',$m['status']);$this->assertNull($m['arithmeticBalance']);$this->assertNull($m['pecDeduction']['deducted']);} else{ $expected=['payable'=>['payable','708','200','0'],'capped'=>['balanced','0','1408','592'],'recoverable'=>['recoverable','-500','1408','592'],'prior-use'=>['payable','1208','200','0']][$name]; $this->assertSame($expected[0],$m['status']); foreach(['arithmeticBalance'=>1,'deducted'=>2,'remaining'=>3]as$field=>$index)$this->assertSame(['numerator'=>$expected[$index],'denominator'=>'1'],$field==='arithmeticBalance'?$m[$field]:$m['pecDeduction'][$field]); } if($previous!==null)$this->assertSame($previous,$saved['history'][0]); $previous=$saved['result']; if(getenv('INVESTMOZ_PEC_QA_OUTPUT')==='1')file_put_contents(base_path('outputs/irpc-l8-pec-20261027/recovered-'.$name.'.json'),json_encode($back,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE)); } $preserved=[]; foreach($protected as$table=>$before){ $after=$snapshot($table); $this->assertSame($before,array_intersect_key($after,$before),'Existing records changed: '.$table); $preserved[$table]=['existing_rows'=>count($before),'unchanged'=>true]; } if(getenv('INVESTMOZ_PEC_QA_OUTPUT')==='1')file_put_contents(base_path('outputs/irpc-l8-pec-20261027/existing-records-preservation.json'),json_encode(['database'=>$target->name,'tables'=>$preserved,'transaction_rollback'=>true],JSON_THROW_ON_ERROR|JSON_PRETTY_PRINT)); } }