feat(iva): add conditional agropecuary operations in QA

This commit is contained in:
2026-10-24 14:53:23 +02:00
parent 0aac0d1555
commit 33d18b9efc
7 changed files with 140 additions and 5 deletions
@@ -5766,5 +5766,54 @@
"installed-public-delta.json": "c4e97e293dc01dd24eebdef3e7d91de281203dd6c9d671dadfccf13b0acc3c45",
"manifest-served.json": "b00f59904a5709fbcd8eaa6b51ac8dc421ddfc8dfd2e0ce18d133240150c8810"
}
},
"iva_l1_g2_agro_qa_20261024": {
"candidate": "CANDIDATE_G2E",
"base_delivered": "3b788ec0",
"base_receipt": "0aac0d15",
"status": "demonstrated_QA_not_installed",
"group": "G2E within G2",
"branches": [
"AUD-SIM-L1-P033",
"AUD-SIM-L1-P034",
"AUD-SIM-L1-P036",
"AUD-SIM-L1-P044"
],
"treatments": [
"industrial_feed",
"industrial_feed_inputs",
"veterinary_goods",
"agricultural_services"
],
"scope": "2026/MZN;9(12)(f/g/i),9(15);19(1)(b)(v) for feed only;field05/07",
"tests": {
"frontend": 2,
"api_tests": 1,
"api_assertions": 14,
"UI_to_API_to_report": true,
"types": "passed",
"build": "passed"
},
"preservation": "Five frozen books unchanged/current without recalculation;17delivered matrix rows and all prior receipt objects unchanged",
"counts": {
"delivered": 17,
"demonstrated_QA": 4,
"functional_pending": 111,
"documentary_pending": 1,
"total": 133
},
"homologation_unchanged": true,
"P001_blocks_independent": false,
"L1_complete": false,
"artifacts": {
"agro-model.json": "57de3b3ac2dcbfeca14b6bdb63a0055ec1f8841a07c91d725eca1c5841593b71",
"agro-report.html": "fbea39db535d79524460fdd6c99ff68a80270a0f4cd978899650fd0b89188cd4",
"api-ui-tests.xml": "4917f20b54e509feb3ddbf3a24fc1d9156d0b0bcf86730362fb9eff880fd11ee",
"article9-15.png": "d8ca06d08782afb6fccc7b88f99facd61523b6c3eb361c4b29f824161b475879",
"recovered.json": "e63a168aee15944cb3e8419eb4aa07e175ca2b1191d742a73204c7c0082bbf2a",
"report-qa.png": "576f1ed2591431e79f3b48509f822492148147d5738ec9c5d1b0dc675c6e2d58",
"source-11.png": "fae5e1144993b9d1b3beaca692b30429050de4fe3af8935e48caf0094d1b23ae",
"ui-calculated.json": "4617e7264a01ce2b40fdba1a32dd14e8808980429dee73fe97e6a45cb215a86c"
}
}
}
@@ -1,5 +1,25 @@
# Rastreabilidade, utilização e formação
## 24/10/2026 — G2E agropecuário demonstrado em QA
**Candidata CANDIDATE_G2E; quatro ramos P033/P034/P036/P044, quatro tratamentos.** Continuação do G2 existente sobre a entrega3b788ec0/recibo0aac0d15;17ramos entregues preservados,semrepetirensaiosaceites. Homologação inalterada;L1aberto.
| Ramo | Operação/condições | Correspondência |
| --- | --- | --- |
| P033 | Bens resultantes da produção industrial de rações para animais de reprodução e abate para consumo humano | 05;9(12)(f),19(1)(b)(v),comdireitoàdeduçãonascondiçõeslegais |
| P034 | Grão de soja,bagaço de soja,soja integral,farinha de peixe,farinha de carne,pós de osso,monofosfato de cálcio,lisina,metionina;matéria-prima para essa produção industrial/destino | 07;9(12)(g),19(1),sem direito nesta operação |
| P036 | Agulhas,seringas e medicamentos de uso veterinário | 07;9(12)(i),19(1),sem direito nesta operação |
| P044 | Abertura de canais,ceifa,drenagem,água para irrigação,limpeza de valas de drenagem,pulverização da terra,efectuadas no âmbito agrícola | 07;9(15),19(1),sem direito nesta operação |
**Fonte/período:** CIVA republicado Lei13/2016 PDF10/p.1426(268),9(12)(f/g/i),9(15);PDF15/p.1426(273),19(1),particularmente19(1)(b)(v),que enumera12(f),não12(g/i)nem15. Lei22/2022 art.1 PDF2/p.2252(26) mantém estas alíneas/número. Renúncia11,PDF11/p.1426(269),abrange9(7)(b–d),não estes quatro ramos; não foi acrescentado impedimento genérico por renúncia. Reutilizado cotejo posterior aceite:Lei16/2020afecta9(13);Lei10/2025nãoaltera9/11nem19(1). Aplicação técnica Janeiro–Dezembro2026/MZN;semcálculohistóricopresumido.P001nãoafectaestesramos. Originais já existentes,preservados.
**Implementação:** quatro opções/condições específicas no motor existente;semreconstrução do simulador,novoformulário,schema,API,migração,importação,permissão ou regra fiscal de servidor. Reutiliza oportunidade,localização,moeda,valor,representação do preço,período e campos de fundamento/condições. P033 não confunde isenção com taxa zero nem gera dedução automática de compras:documento,afectação e elegibilidade continuam no percurso próprio de aquisições. Nosoutrosramos,a ausência da enumeração do19(1)éconservada. Nãoestenderabenefícioaqualquerprodutoveterinário,ração,obraoufornecimentodeágua.
**Provas dirigidas:**2testesfrontendpassaram:quatroramos,100,00MZNcada,preçolíquido/incluído;05=100,00;07=300,00;IVA0,00;ausência individualdecadacondição/fundamento,moedaincompatível/períodoforacobertura→indeterminado. FixturecongeladadaQA G2D preserva cinco livros anteriores integralmente,comchavesactuais,semrecálculo. APIprivadaPOST→GET,baseQAisolada `simulator_fiscal_delta_20261021_test:55441`,guardadedestino/transacçãorevertida,1teste/14asserções,snapshotintegralrecuperadoe05/07conferidos. Interface real:afectaçãodosinsumosdesconhecida→indeterminado;completada→calculado/guardadorevisão3;payloadreal→API→recuperação→relatórioHTML. Relatórioquatrooperações,contexto314/Manica,2026-06,MZN,origens/fontes/versão;05/07coerentes,semoperaçõesdosoutroscontextos. Tipos/compilação passaram. Renderizadores não alterados;Word/PDF/fracções aceites reutilizados,semnovaafirmaçãodepaginação.
**Saldo:**133IDs=17entregues+4QA+111funcionaispendentes+P001documental.G2total32=13entregues+4QA+15pendentes.Motor36tratamentoscondicionados=10iniciais+26dosgrupos;duasopçõesindeterminadasmantidas. IDsnenhumfundido/eliminado. Estatísticas/IAadiadas. EntregafuturaGitcomconferênciafrescadodestino/concorrência,backup/restauroedelta;nenhumadisponibilizaçãoexecutadanestapassagem. Contençãodeveconservarcatálogo/leitores/snapshots,históricoerelatórios;patchcompatívelanteriornãoseaplicaautomaticamente. Artefactosprivados `outputs/iva-l1-g2-agro-20261024/`.
## 24/10/2026 — G2C/G2D entregues na homologação3b788ec0
**Cinco ramos entregues:**P013–P015/P024–P025, sete tratamentos condicionais. `main` actualizado por fast-forward490527b9→3b788ec0, semforce, após consulta fresca do remoto e destino autenticado, preservando os fechos anteriores. Instalação/activação pelo webhook/instalador existente. Revisão efectivamente servida3b788ec0, manifesto/assets do novo catálogo e entrada do simuladorHTTP200 conferidos; sem novas execuções privadas sintéticas no activo. Controlos automáticos normais do instalador conservaram o processo de entrega; não se repetiram rondas manuais das provas QA aceites.
File diff suppressed because one or more lines are too long
+4
View File
@@ -33,6 +33,10 @@ const culturalTreatments:OperationTreatment[] = ([false,true] as const).flatMap(
});
culturalTreatments.push({id:'statutory_membership',label:'Serviços colectivos aos associados por quota estatutária',field:'07',rate:0,article:'CIVA arts.9(2)(g),10(2),19(1)',source:culturalSource,conditions:[internalOperation,...nonprofitConditions,'Serviços efectuados no interesse colectivo dos próprios associados por organismo sem finalidade lucrativa','Objectivos de natureza política, sindical, religiosa, patriótica, filantrópica, recreativa, desportiva, cultural, cívica ou de representação de interesses económicos, identificados','A única contraprestação é uma quota fixada nos respectivos estatutos; não pagamentos adicionais por serviços individuais']});
export const operationTreatments:OperationTreatment[] = [
{id:'industrial_feed',label:'Rações de produção industrial para animais elegíveis',field:'05',rate:0,article:'CIVA arts.9(12)(f),19(1)(b)(v)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(12)(f); PDF15, p.1426(273),19(1)(b)(v); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(12)(f). Âmbito técnico2026/MZN',conditions:[internalOperation,'Transmissão de bens resultantes de actividade industrial de produção de rações, identificada; não presumir isenção de qualquer alimento para animais','Rações destinadas à alimentação de animais de reprodução e abate para consumo humano, com destino identificado']},
{id:'industrial_feed_inputs',label:'Insumos enumerados para produção industrial de rações',field:'07',rate:0,article:'CIVA arts.9(12)(g),19(1)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(12)(g); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(12)(g). Âmbito técnico2026/MZN',conditions:[internalOperation,'Bem identificado na enumeração: grão de soja, bagaço de soja, soja integral, farinha de peixe, farinha de carne, pós de osso, monofosfato de cálcio, lisina ou metionina','Utilização como matéria-prima na actividade industrial de produção de rações destinadas à alimentação de animais de reprodução e abate para consumo humano, identificada']},
{id:'veterinary_goods',label:'Agulhas, seringas e medicamentos de uso veterinário',field:'07',rate:0,article:'CIVA arts.9(12)(i),19(1)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(12)(i); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(12)(i). Âmbito técnico2026/MZN',conditions:[internalOperation,'Transmissão de agulha, seringa ou medicamento identificado; não qualquer equipamento ou serviço veterinário','Uso veterinário identificado para os bens da operação']},
{id:'agricultural_services',label:'Serviços agrícolas de canais, regadio, drenagem e pulverização',field:'07',rate:0,article:'CIVA arts.9(15),19(1)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(15); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(15). Âmbito técnico2026/MZN',conditions:[internalOperation,'Serviço identificado: abertura de canais, ceifa, drenagem, fornecimento de água para irrigação, limpeza de valas de drenagem ou pulverização da terra','Serviço efectuado no âmbito da actividade agrícola, com afectação identificada; não qualquer obra, limpeza ou fornecimento de água']},
{id:'author_rights',label:'Direitos de autor pelo autor, herdeiro ou legatário',field:'07',rate:0,article:'CIVA arts.9(9)(a),19(1)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(9)(a); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(9). Âmbito técnico2026/MZN',conditions:[internalOperation,'Operação identificada como transmissão de direitos de autor ou autorização para utilização de obra intelectual','Efectuada pelo próprio autor, seu herdeiro ou legatário, com qualidade identificada; não presumir isenção de revenda/intermediação por terceiro']},
{id:'cultural_publications',label:'Jornais, revistas e livros de natureza elegível',field:'07',rate:0,article:'CIVA arts.9(9)(b),19(1)',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(9)(b); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF2, p.2252(26), mantém9(9). Âmbito técnico2026/MZN',conditions:[internalOperation,'Transmissão de jornal, revista ou livro identificado; não qualquer material escolar, serviço editorial ou fornecimento autónomo','Natureza cultural, educativa, técnica ou recreativa da publicação identificada e sustentada; não inferida apenas do nome do fornecedor ou sector']},
...culturalTreatments,
+33
View File
@@ -0,0 +1,33 @@
<?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 IvaAgroDraftTest extends TestCase
{
use DatabaseTransactions;
public function test_agro_context_preserves_accepted_opportunities(): void
{
$target = DB::selectOne('select current_database() as name,inet_server_port() as port');
$this->assertSame('simulator_fiscal_delta_20261021_test', $target->name);
$this->assertSame(55441, (int) $target->port);
config(['investor-path.enabled' => true, 'suitecrm.enabled' => false]);
$this->actingAs(User::factory()->create(['email_verified_at' => now()]));
$draft = json_decode(file_get_contents(getenv('IVA_G2E_INPUT') ?: base_path('outputs/iva-l1-g2-agro-20261024/calculated.json')), true, flags: JSON_THROW_ON_ERROR);
$id = $this->postJson('/api/v1/simulation-drafts', ['personal_snapshot' => [], 'economic_snapshot' => $draft], ['Idempotency-Key' => (string) Str::uuid()])->assertCreated()->json('data.id');
$recovered = $this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk()->json('data.economic_snapshot');
$this->assertSame($draft['modelo_a_snapshot'], $recovered['modelo_a_snapshot']);
$book = json_decode($recovered['modelo_a_snapshot'], true)['salesOperations']['opportunity:314'];
$this->assertCount(4, $book['result']['rows']);
$this->assertSame('300.00', $book['result']['periods'][0]['fields']['07']);
$this->assertSame('100.00', $book['result']['periods'][0]['fields']['05']);
$this->assertSame(json_decode($draft['modelo_a_snapshot'], true)['salesOperations']['opportunity:310'], json_decode($recovered['modelo_a_snapshot'], true)['salesOperations']['opportunity:310']);
$this->assertSame(json_decode($draft['modelo_a_snapshot'], true)['salesOperations']['opportunity:309'], json_decode($recovered['modelo_a_snapshot'], true)['salesOperations']['opportunity:309']);
foreach ($book['result']['rows'] as $row) $this->assertSame('0.00', $row['vat']);
if (getenv('IVA_G2E_RECOVERED')) file_put_contents(getenv('IVA_G2E_RECOVERED'), json_encode($recovered, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE));
}
}
File diff suppressed because one or more lines are too long
+28
View File
@@ -0,0 +1,28 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import fs from 'node:fs';
import {operationTreatments,newSalesOperation,evaluateSalesOperation,recordSales,saveSalesBook,salesBook,salesCurrent} from '../../resources/js/lib/iva-operations.ts';
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
const ids=['industrial_feed','industrial_feed_inputs','veterinary_goods','agricultural_services'];
function seed(){return JSON.parse(fs.readFileSync(new URL('./fixtures/iva-publications.json',import.meta.url),'utf8'));}
function fixture(){const draft=seed();draft.context_opportunity='opportunity:314';draft.project_title='SYNTHETIC QA — G2E social';
let book={currency:'MZN',rows:ids.map((id,i)=>({...newSalesOperation(`g2e-${i}`,'2026-06','MZN'),description:`SYNTHETIC QA ${id}`,establishment:'SYNTHETIC QA equipamento Manica',amount:'100',basis:i%2?'included':'net',treatment:id,confirmed:operationTreatments.find(t=>t.id===id).conditions.map((_,n)=>n),evidence:'SYNTHETIC QA — natureza, entidade, reconhecimento e condições cumulativas pressupostos documentados; sem certificação'})),periods:[{period:'2026-06',complete:true}]};book=recordSales(draft,book);draft.modelo_a_snapshot=saveSalesBook(draft,book);return {draft,book};}
test('G2E four branches require their own operation and eligibility conditions',()=>{
const {book}=fixture();for(const row of book.rows){const rule=operationTreatments.find(t=>t.id===row.treatment),r=evaluateSalesOperation(row,'MZN');assert.equal(r.field,row.treatment==='industrial_feed'?'05':'07');assert.equal(r.net,'100.00');assert.equal(r.vat,'0.00');assert.equal(r.gross,'100.00');assert.match(r.article,/9\((12|15)\)/);
assert.equal(rule.conditions.length,3);
for(const missing of row.confirmed)assert.equal(evaluateSalesOperation({...row,confirmed:row.confirmed.filter(n=>n!==missing)},'MZN').vat,null);
assert.equal(evaluateSalesOperation({...row,evidence:''},'MZN').vat,null); assert.equal(evaluateSalesOperation({...row,period:'2025-06'},'MZN').vat,null); assert.equal(evaluateSalesOperation(row,'USD').vat,null);
}
assert.equal(book.result.periods[0].fields['07'],'300.00');assert.equal(book.result.periods[0].fields['05'],'100.00');assert.match(book.result.rows[0].reason,/com direito/);assert.ok(book.result.rows.slice(1).every(r=>r.reason.includes('sem direito')));
});
test('new agro context round-trips and reports only its operations, preserving five accepted books without recalculation',()=>{
const {draft,book}=fixture(),original=seed();const old=JSON.parse(original.modelo_a_snapshot).salesOperations;
const recovered=JSON.parse(JSON.stringify(draft)),store=JSON.parse(recovered.modelo_a_snapshot).salesOperations;
for(const id of ['opportunity:309','opportunity:310','opportunity:311','opportunity:312','opportunity:313']){assert.deepEqual(store[id],old[id]);assert.equal(salesCurrent({...recovered,context_opportunity:id},store[id]),true);}
assert.equal(salesCurrent(recovered,salesBook(recovered)),true);
const model=JSON.stringify(createProjectDossierReport(recovered,{selectedSections:new Set(['finance'])}));
for(const token of [...ids,'300.00','opportunity:314','Manica','2026-06','MZN'])assert.ok(model.includes(token),token);
for(const token of ['financial_stamp','patient_transport','social_assistance_public','statutory_membership','author_rights'])assert.equal(model.includes(token),false);
assert.equal(book.result.rows.length,4);assert.equal(draft.currency,original.currency);assert.deepEqual(draft.selection_labels,original.selection_labels);
});
if(process.env.IVA_G2E_OUT)fs.writeFileSync(process.env.IVA_G2E_OUT,JSON.stringify(fixture().draft,null,2));