Merge remote-tracking branch 'origin/main' into qa/editorial-fase1-20261113
tests / ci (push) Canceled after 0s
tests / ci (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class IrpcAnnualNoncivilDraftTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function test_period_survives_native_recovery_without_changing_the_independent_annual_result(): void
|
||||
{
|
||||
$target = DB::selectOne('select current_database() as name,inet_server_port() as port');
|
||||
$this->assertSame('investmoz_demography_test', $target->name);
|
||||
$this->assertSame(55441, (int) $target->port);
|
||||
config(['investor-path.enabled' => true, 'suitecrm.enabled' => false]);
|
||||
$actor = User::factory()->create();
|
||||
$this->actingAs($actor);
|
||||
$id = null;
|
||||
$etag = null;
|
||||
foreach (['three', 'single', 'missing', 'changed'] as $name) {
|
||||
$snapshot = json_decode(file_get_contents(base_path('outputs/irpc-noncivil-20261114/'.$name.'.json')), true, flags: JSON_THROW_ON_ERROR);
|
||||
$personal = ['person_type' => $snapshot['person_type']];
|
||||
unset($snapshot['person_type']);
|
||||
$payload = ['personal_snapshot' => $personal, 'economic_snapshot' => $snapshot];
|
||||
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($snapshot['modelo_a_snapshot'], $back['modelo_a_snapshot']);
|
||||
$book = json_decode($back['modelo_a_snapshot'], true, flags: JSON_THROW_ON_ERROR)['irpcAnnual'][$snapshot['context_opportunity']];
|
||||
$this->assertCount(1, $book['history']);
|
||||
$this->assertArrayHasKey('advancePeriod', $book['result']['model']);
|
||||
$this->assertSame($book['history'][0]['model']['arithmeticBalance'], $book['result']['model']['arithmeticBalance']);
|
||||
$this->assertSame($book['pecObligation'], $book['result']['model']['input']['pecObligation']);
|
||||
$this->assertSame($book['ppcObligation'], $book['result']['model']['input']['ppcObligation']);
|
||||
$this->assertSame('2026', $book['ppcObligation']['year']);
|
||||
$this->assertSame($book['advancePeriodDeclaration'], $book['result']['model']['input']['advancePeriodDeclaration']);
|
||||
$this->assertSame('SYNTHETIC effective activity2020', $book['pecObligation']['activityReference']);
|
||||
file_put_contents(base_path('outputs/irpc-noncivil-20261114/recovered-'.$name.'.json'), json_encode($back, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import {periodAdvanceCase} from './irpc-advance-period-case.mjs';
|
||||
import {newAdvancePeriodDeclaration,advancePeriodBasis,annualAdvancePeriod} from '../../../resources/js/lib/irpc-annual-settlement.ts';
|
||||
import {newPecPlan} from '../../../resources/js/lib/irpc-pec-plan.ts';
|
||||
export function noncivilCase(){
|
||||
const c=periodAdvanceCase('noncivil');c.b.ppcObligation.previousFullCalendarYear='no';
|
||||
c.b.advancePeriodDeclaration={...newAdvancePeriodDeclaration(c.b.subjectNuit,c.b.year,c.period),currentReference:'SYNTHETIC documented authorised annual period CIRPC7(2), continued activity',previousReference:'SYNTHETIC prior annual period and amount/source correspondence',confirmed:'yes'};
|
||||
c.b.advancePeriodDeclaration.ppcBasisKey=advancePeriodBasis(c.b,'ppc');c.b.advancePeriodDeclaration.pecBasisKey=advancePeriodBasis(c.b,'pec');
|
||||
c.period=annualAdvancePeriod(c.d,c.b);
|
||||
c.b.pecObligation.plan={...newPecPlan(c.period),mode:'three',june:'10000',august:'15000',october:'15000',reference:'SYNTHETIC reviewed noncivil cash distribution'};
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import {createRequire} from 'node:module';
|
||||
import {compileFunction} from 'node:vm';
|
||||
import React from 'react';
|
||||
import {renderToStaticMarkup} from 'react-dom/server';
|
||||
import ts from 'typescript';
|
||||
import * as annual from '../../resources/js/lib/irpc-annual-settlement.ts';
|
||||
import * as planLib from '../../resources/js/lib/irpc-pec-plan.ts';
|
||||
import * as rational from '../../resources/js/lib/fiscal-rational.ts';
|
||||
import {noncivilCase} from './helpers/irpc-annual-noncivil-case.mjs';
|
||||
const require=createRequire(import.meta.url);
|
||||
function load(name,resolver){const module={exports:{}};const code=ts.transpileModule(fs.readFileSync(new URL('../../resources/js/components/'+name,import.meta.url),'utf8'),{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022,jsx:ts.JsxEmit.ReactJSX}}).outputText;compileFunction(code,['require','module','exports'])(resolver,module,module.exports);return module.exports;}
|
||||
function all(tree){if(!tree||typeof tree!=='object')return [];return [tree,...React.Children.toArray(tree.props?.children).flatMap(all)];}
|
||||
const annualUi=()=>load('simulation-irpc-annual.tsx',n=>n==='@/lib/irpc-annual-settlement'?annual:n.startsWith('./')?new Proxy({},{get:()=>()=>null}):require(n));
|
||||
test('period preparation suggests dates without evidence or silent confirmation; editing retains deliberate inputs',()=>{
|
||||
const {d,b}=noncivilCase();delete b.advancePeriodDeclaration;let changed;
|
||||
const C=annualUi().SimulationIrpcAdvancePeriodDeclaration;
|
||||
let tree=C({draft:d,book:b,onChange:v=>changed=v});all(tree).find(e=>e.type==='button').props.onClick();
|
||||
assert.equal(changed.currentFrom,'2025-07-01');assert.equal(changed.previousFrom,'2024-07-01');assert.equal(changed.confirmed,'');assert.equal(changed.previousReference,'');
|
||||
b.advancePeriodDeclaration={...changed,currentReference:'SYNTHETIC chosen reference',previousReference:'SYNTHETIC prior reference',confirmed:'yes'};
|
||||
tree=C({draft:d,book:b,onChange:v=>changed=v});
|
||||
all(tree).find(e=>e.props?.['aria-label']==='Fonte e correspondência do período anterior').props.onChange({target:{value:'SYNTHETIC corrected source'}});
|
||||
assert.equal(changed.confirmed,'');assert.equal(changed.currentReference,'SYNTHETIC chosen reference');assert.equal(changed.previousReference,'SYNTHETIC corrected source');
|
||||
});
|
||||
test('reconfirmation retains periods and deliberate references while binding changed financial amounts',()=>{
|
||||
const {d,b}=noncivilCase(),old=structuredClone(b.advancePeriodDeclaration);b.ppcObligation.previousTax='200000';let changed;
|
||||
const tree=annualUi().SimulationIrpcAdvancePeriodDeclaration({draft:d,book:b,onChange:v=>changed=v});
|
||||
all(tree).find(e=>e.type==='button'&&String(e.props.children).includes('Reconferi')).props.onClick();
|
||||
assert.equal(changed.currentReference,old.currentReference);assert.equal(changed.previousFrom,old.previousFrom);assert.equal(changed.confirmed,'yes');assert.notEqual(changed.ppcBasisKey,old.ppcBasisKey);assert.equal(changed.pecBasisKey,old.pecBasisKey);
|
||||
});
|
||||
test('PEC explicit period binding preserves cash distribution and renders actual relative months',()=>{
|
||||
const C=load('simulation-irpc-pec-plan.tsx',n=>n==='@/lib/irpc-pec-plan'?planLib:n==='@/lib/fiscal-rational'?rational:require(n)).SimulationIrpcPecPlan;
|
||||
const {b,period}=noncivilCase(),plan={...b.pecObligation.plan};delete plan.periodFrom;delete plan.periodTo;let changed;
|
||||
const props={plan,total:{numerator:'40000',denominator:'1'},notApplicable:false,year:'2026',period,onChange:v=>changed=v};
|
||||
const tree=C(props);all(tree).find(e=>e.type==='button'&&String(e.props.children).includes('Conferi')).props.onClick();
|
||||
assert.equal(changed.june,'10000');assert.equal(changed.august,'15000');assert.equal(changed.reference,plan.reference);assert.equal(changed.periodFrom,'2025-07-01');
|
||||
const html=renderToStaticMarkup(React.createElement(C,{...props,plan:changed}));
|
||||
for(const month of ['2025-12','2026-02','2026-04'])assert.match(html,new RegExp(month));
|
||||
assert.ok(!html.includes('Conferi a distribuição para'));
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {noncivilCase} from './helpers/irpc-annual-noncivil-case.mjs';
|
||||
import {advanceCalendar,newAdvancePeriodDeclaration} from '../../resources/js/lib/irpc-advance-calendar.ts';
|
||||
import {calculatePpcObligation} from '../../resources/js/lib/irpc-ppc-obligation.ts';
|
||||
import {calculatePecObligation} from '../../resources/js/lib/irpc-pec-obligation.ts';
|
||||
import {calculatePecPlan} from '../../resources/js/lib/irpc-pec-plan.ts';
|
||||
import {annualAdvancePeriod,advancePeriodBasis,annualAdvanceCashflow,recordAnnual,saveAnnualBook,annualBook,annualCurrent,annualHtml} from '../../resources/js/lib/irpc-annual-settlement.ts';
|
||||
const f=n=>({numerator:String(n),denominator:'1'});
|
||||
test('documented annual noncivil periods reuse exact estimates and relative PPC PEC months',()=>{
|
||||
const {b,period}=noncivilCase(),before=JSON.stringify(b);const ppc=calculatePpcObligation(b.ppcObligation,b.subjectNuit,b.year,b.assessment,period),pec=calculatePecObligation(b.pecObligation,b.subjectNuit,b.year,b.assessment,period);
|
||||
assert.deepEqual(ppc.total,f(72000));assert.deepEqual(ppc.schedule.map(r=>r.month),['2025-11','2026-01','2026-03']);assert.deepEqual(pec.total,f(40000));assert.deepEqual(pec.months,['2025-12','2026-02','2026-04']);
|
||||
const joint=annualAdvanceCashflow(b,period);assert.deepEqual(joint.total,f(112000));assert.deepEqual(joint.rows.map(r=>r.month),['2025-11','2025-12','2026-01','2026-02','2026-03','2026-04']);assert.equal(JSON.stringify(b),before);
|
||||
});
|
||||
test('missing evidence, identity mismatch, nonadjacent and short previous periods cannot qualify the annual recorte',()=>{
|
||||
for(const changes of [{confirmed:''},{currentReference:''},{previousReference:''},{subjectNuit:'999999999'},{currentFrom:'2025-08-01'},{previousFrom:'2025-01-01'},{previousTo:'2025-05-31'}]){
|
||||
const {d,b}=noncivilCase();Object.assign(b.advancePeriodDeclaration,changes);assert.equal(annualAdvanceCashflow(b,annualAdvancePeriod(d,b)).total,null,JSON.stringify(changes));
|
||||
}
|
||||
const missing=noncivilCase();missing.b.advancePeriodDeclaration.previousReference='';const result=calculatePpcObligation(missing.b.ppcObligation,missing.b.subjectNuit,missing.b.year,missing.b.assessment,annualAdvancePeriod(missing.d,missing.b));assert.ok(result.pending.length);assert.ok(!result.pending.join(' ').includes('exercício civil completo2025'));
|
||||
assert.equal(advanceCalendar(null,'').mode,'unavailable');
|
||||
});
|
||||
test('editing one component invalidates only its confirmed amount correspondence',()=>{
|
||||
const {d,b}=noncivilCase();b.ppcObligation.previousTax='200000';let m=annualAdvanceCashflow(b,annualAdvancePeriod(d,b));assert.equal(m.ppcKnown,false);assert.equal(m.pecKnown,true);assert.equal(m.total,null);
|
||||
b.advancePeriodDeclaration.ppcBasisKey=advancePeriodBasis(b,'ppc');m=annualAdvanceCashflow(b,annualAdvancePeriod(d,b));assert.equal(m.ppcKnown,true);assert.deepEqual(m.total,f(193000));
|
||||
});
|
||||
test('civil cash choices are retained without automatic displacement and require explicit noncivil binding',()=>{
|
||||
const {b,period}=noncivilCase();delete b.pecObligation.plan.periodFrom;delete b.pecObligation.plan.periodTo;let m=annualAdvanceCashflow(b,period);assert.equal(m.pecKnown,false);assert.equal(b.pecObligation.plan.june,'10000');
|
||||
b.pecObligation.plan.periodFrom=period.from;b.pecObligation.plan.periodTo=period.to;m=annualAdvanceCashflow(b,period);assert.deepEqual(m.total,f(112000));
|
||||
const p={...b.pecObligation.plan,mode:'single',singleMonth:'2026-01'};assert.deepEqual(calculatePecPlan(p,f(40000),false,'2026',period).rows,[{month:'2026-01',amount:f(40000)}]);p.singleMonth='2026-07';assert.equal(calculatePecPlan(p,f(40000),false,'2026',period).rows.length,0);
|
||||
});
|
||||
test('source changes preserve the declaration but require reconfirmation; excluded historical and start cases stay separate',()=>{
|
||||
const {d,b}=noncivilCase();const old=JSON.stringify(b.advancePeriodDeclaration);const period={...annualAdvancePeriod(d,b),from:'2025-08-01',to:'2026-07-31'};assert.equal(annualAdvanceCashflow(b,period).total,null);assert.equal(JSON.stringify(b.advancePeriodDeclaration),old);
|
||||
b.pecObligation.previousTurnover='0';b.advancePeriodDeclaration.pecBasisKey=advancePeriodBasis(b,'pec');assert.equal(calculatePecObligation(b.pecObligation,b.subjectNuit,b.year,b.assessment,annualAdvancePeriod(d,b)).total,null);
|
||||
b.pecObligation.activityStartYear='2026';b.advancePeriodDeclaration.pecBasisKey=advancePeriodBasis(b,'pec');assert.equal(calculatePecObligation(b.pecObligation,b.subjectNuit,b.year,b.assessment,annualAdvancePeriod(d,b)).total,null);
|
||||
});
|
||||
test('annual recovery freezes qualified periods and keeps the independent settlement and history unchanged',()=>{
|
||||
const {d,b}=noncivilCase();const prior=recordAnnual(d,{...b,ppcObligation:undefined,pecObligation:undefined},'2026-11-14T07:00:00Z');const next=recordAnnual(d,{...prior,ppcObligation:b.ppcObligation,pecObligation:b.pecObligation},'2026-11-14T07:01:00Z');assert.deepEqual(next.result.model.arithmeticBalance,prior.result.model.arithmeticBalance);
|
||||
d.modelo_a_snapshot=saveAnnualBook(d,next);const back=annualBook(d);assert.equal(annualCurrent(d,back),true);assert.equal(back.history.length,1);assert.deepEqual(annualAdvanceCashflow(back,back.result.model.advancePeriod).total,f(112000));assert.match(annualHtml(d),/2025-11/);
|
||||
const frozen=JSON.stringify(back.result.model.advancePeriod);back.advancePeriodDeclaration.previousReference='SYNTHETIC revised reference';assert.equal(JSON.stringify(back.result.model.advancePeriod),frozen);assert.equal(annualCurrent(d,back),false);
|
||||
});
|
||||
Reference in New Issue
Block a user