feat(iva): implement G2K pharmaceutical manufacturing inputs in QA

This commit is contained in:
2026-10-24 16:05:55 +02:00
parent eb9e0dbc60
commit 8882dc54d0
10 changed files with 340 additions and 10 deletions
@@ -1,5 +1,36 @@
# Rastreabilidade, utilização e formação
## 24/10/2026 — G2K / P008 demonstrado em QA
**Um ramo, um tratamento: `pharma_manufacturing_inputs`.** Homologação permanece em `e45a1394`, recibo `eb9e0dbc`; os34 ramos entregues, incluindo G2I/G2J e calendário, continuam encerrados. L1 aberto; P001 exclusivamente05/06. Estatísticas/IA adiadas.
### Fonte, cobertura e correspondência executável
CIVA republicado Lei13/2016, PDF9/p.1426(267),9(1)(g): transmissão pelo próprio estabelecimento público ou privado integrado no Serviço Nacional de Saúde, de bens a utilizar como matérias-primas, produtos intermédios ou componentes para fabrico de medicamentos, constantes da Pauta e discriminados no AnexoIII. Não basta que o adquirente seja hospital nem o sector do investimento. Sem inscrição, aprovação adicional ou certificação inventadas. Artigo19(1),PDF15/p.1426(273): campo07, isenção sem direito nesta operação; não se deduzem compras automaticamente.
Aviso BR89/2017,PDF1/p.569,rectifica os anexosI/II/III. Lei22/2022,art.3(1),PDF4/p.2252(28),substituiAnexoIII,PDF12–16/p.2252(36)–(40),efeitos01/01/2023 peloart.6. As cinco páginas foram conferidas visualmente. Lei3/2025,art.1,altera9(13),sem alterar9(1)(g)/AnexoIII; Lei10/2025,art.1,enumera alterações sem9(1)(g). Aplicação técnica deste incremento: Janeiro–Dezembro2026/MZN; nenhuma extensão histórica do motor.
Catálogo `annexIII-lei22-2022/1`:170linhas documentais/169códigos distintos, todas com identidade própria, código, designação e página. `2912.19.00` aparece duas vezes com designações diferentes: identidades084/085,sem fusão nem escolha automática pelo código. `2935.` permanece como impresso, sem completar dígitos. Continuações de2827.39.00 e2922.49.00 conservam ambas as páginas. A transposição de letras da camada textual em«Antibióticos» foi ajustada ao texto impresso, sem alterar o original. As demais grafias do exemplar são preservadas; o catálogo não presta classificação aduaneira automática.170linhas não são170ramos nem170desenvolvimentos.
### Dados e percurso
Reutilizados oportunidade,localização,moeda original,estabelecimento,valor,preço líquido/IVA incluído,período e fundamento. Único novo campo fiscal opcional nas linhas deste tratamento: `pharmaAnnexItem`,identidade da posição. Pesquisa por código/designação apenas filtra opções; conserva a selecção actual, mesmo fora do filtro. Os dados antigos dos outros tratamentos não ganham campos obrigatórios. Condições específicas no controlo existente: operação interna, integração do transmitente noSNS, uso no fabrico e correspondência cumulativa código/designação. Desconhecido/código livre/outra edição/anexo/fundamento em falta→indeterminado,sem conversão emzero.
Selecção,identidade/edição/página,condições e fundamento seguem no snapshot e no relatório da oportunidade em tratamento. Alterar para outra linha com o mesmo código torna o resultado anterior histórico; não o substitui automaticamente. Não se alteraram schema,rotas,permissões,fórmulas,calendário nem regras entregues. A chave de actualidade mantém-se limitada aos tratamentos usados em cada livro.
### Provas novas e preservação
3testesfrontend:170linhas enumeradas e rastreáveis,duplicações/posição incompleta/continuações,condições cumulativas,informação insuficiente,moeda/período divergentes,troca entre identidades com o mesmo código,relatório/recuperação. Fixture congelada G2I/G2J preserva11livros completos e actuais sem recálculo, incluindo `production-option/2`. Não foram repetidos os ensaios aceites dos34ramos.
APIprivada POST→GET naQAisolada `simulator_fiscal_delta_20261021_test:55441`,com guarda de destino e transacção revertida:1teste/27asserções. Interface real: pesquisa2912.19 conserva escolha1108.11.00; posição em falta→indeterminado; integração do transmitente retirada→indeterminado; reposta→cálculo/guarda revisão4; actualização do ecrã recupera estado. Payload real da interface→API→recuperação→relatórioHTML visualmente conferido. Cinco linhas de100MZN,preço líquido/incluído,07=500,00;05=0,00;IVA0,00;contexto320/Manica/2026-12;as duas identidades2912.19.00 e2935. preservadas. Tipos/build passaram. Exportadores inalterados: provas Word/PDF/fracções aceites reutilizadas, sem nova afirmação de paginação. Artefactos privados `outputs/iva-l1-g2-pharma-inputs-20261024/`.
### Reconciliação documental, sem implementar G3
Obtido o original oficial integral [BR95/2025,Lei3/2025](../simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf),2páginas,origem no arquivo de boletins,hash `e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358`. Art.1/PDF1/p.478(1):9(13)a–e e termo31/12/2025;PDF2/p.478(2):9(13)f,art.2 entrada na publicação eAnexoII. Registado no inventário de fontes existente e nas dependências deP038–P043; deixa de ser correcta a pendência«texto integral ainda não obtido». Estes seis IDs continuam funcionais pendentes: transição/cessação e condições por executar; não se prorroga o benefício para2026. Nenhum cálculo deG3 foi activado e nenhum original publicado/importado na base. P045 conserva a dependência específica relativa a9(16),não resolvida por esta fonte.
**Saldo:34 entregues+1QA(G2K/P008)+97funcionais pendentes+P001=133IDs.** G2:32=30entregues+1QA+P035pendente. Motor73tratamentoscondicionados+2opçõesindeterminadas. G2K fica preparado para a próxima entrega conjunta pelo processoGit existente, com destino/main e backup/restauro frescos; esta passagem não declara disponibilização. P00105/06 eL1 permanecem abertos.
## 24/10/2026 — G2I/G2J entregues na homologação e45a1394
Cinco ramos P016/P019–P022, nove tratamentos, disponibilizados em `e45a1394` pelo processo Git existente: fast-forward sobre `d4eae917`, após fetch fresco e conferência autenticada do destino. Calendário de G2I corrigido por Código Civil279(c)/296 e CIVA11(3): termo às24h, último dia do mês quando necessário, declaração antes da expiração e efeitos no Janeiro seguinte sem antecipar permanência mínima. Só as três opções G2I mudam de chave; resultados anteriores preservados no histórico. Os29ramos anteriormente entregues mantêm os fechos.
@@ -606,3 +606,4 @@ C:\laragon\www\portal-investidor\docs\investmoz\v2\auditoria-portal\legado-sitem
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\segmentar processos v1.docx,104147,bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5,.docx,Original integral907parágrafos/14tabelas; relações externas/notas/alterações verificadas; hash e cópia privada preservados. Identidade binária com v1(3).docx confirmada pelo responsável em 11/10/2026; v1.docx é o nome local do mesmo exemplar.,PrivadoQA/biblioteca recurso29,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,"v1; propriedadeOOXMLrevision15; modificado11/10/2026 12:29UTC; mesmo exemplar de v1(3).docx, confirmado pelo responsável em 11/10/2026.",Exemplar acessível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\segmentar processos v1.docx,bf26caeee0437a8d292bf29be59247e2862c14e79b5ae465c00322747af72af5,Idêntico ao hash histórico,Hash original preservado; alteração de nome/caminho não cria outro documento/requisito.
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~$gmentar processos v1.docx,162,dd30703646feabe737708b9072861ce24e7ebd953e25847edcb23143383d5ae2,.docx,Inventariado integralmente no mesmo diretório antes da seleção; conteúdo não promovido a implementação. Not a valid DOCX ZIP; inventoried without discarding.,Origem acessível; divulgação não inferida.,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,Nome/hash do exemplar; versão substantiva não inferida.,Original indisponível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~$gmentar processos v1.docx,,Não aplicável/sem bytes disponíveis,"Ficheiro temporário Word indisponível; referência histórica preservada, não omitir do inventário."
\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~WRL2698.tmp,20868,fb8a11801469536438e9e85cacc3468d33253d22e94bb366f249d109ba9ab827,.tmp,Inventariado integralmente no mesmo diretório antes da seleção; conteúdo não promovido a implementação. ,Origem acessível; divulgação não inferida.,Nenhum cálculo ativado.,Documento de programação; não estender aceitação oficial. Original/histórico preservados.,Nome/hash do exemplar; versão substantiva não inferida.,Original indisponível,\\mac\home\Documents\TEMPO\Portal Tempo\Servicos Tempo\Relatorios\novos\~WRL2698.tmp,,Não aplicável/sem bytes disponíveis,"Ficheiro temporário Word indisponível; referência histórica preservada, não omitir do inventário."
https://archive.gazettes.africa/archive/mz/2025/mz-government-gazette-series-i-supplement-dated-2025-05-21-no-95.pdf,329070,e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358,original oficial PDF,"BR95,I Série,Suplemento,21/05/2025;Lei3/2025 arts.1/2 eAnexoII;2páginas conferidas",Exemplar privado disponível para consulta;sem publicação automática,Não usado em regra/cálculo novo;delimita independência deP008 e próximoG3,Origem oficial identificada;9(13) com termo31/12/2025;sem prorrogação presumida,Lei3/2025 de21/05/2025,Conferido em24/10/2026,C:\laragon\www\portal-investidor\docs\investmoz\simulations\source-archive\BR-95-I-Suplemento-2025-05-21.pdf,e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358,Original preservado porbytes/hash,Aquisição documental apenas;zero importação/publicação em base activa. Fonte aceite conforme decisãoTempo08/10;P038–P043 permanecem funcionais pendentes.
1 Exemplar/caminho Bytes SHA256 Tipo Nota de leitura Disponibilidade Uso em cálculo Situação jurídica/documental Edição/versão identificada Disponibilidade conferida 12/10/2026 Caminho atual/alias SHA256 atual Correspondência binária Observação da reconciliação
606 https://archive.gazettes.africa/archive/mz/2025/mz-government-gazette-series-i-supplement-dated-2025-05-21-no-95.pdf 329070 e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358 original oficial PDF BR95,I Série,Suplemento,21/05/2025;Lei3/2025 arts.1/2 eAnexoII;2páginas conferidas Exemplar privado disponível para consulta;sem publicação automática Não usado em regra/cálculo novo;delimita independência deP008 e próximoG3 Origem oficial identificada;9(13) com termo31/12/2025;sem prorrogação presumida Lei3/2025 de21/05/2025 Conferido em24/10/2026 C:\laragon\www\portal-investidor\docs\investmoz\simulations\source-archive\BR-95-I-Suplemento-2025-05-21.pdf e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358 Original preservado porbytes/hash Aquisição documental apenas;zero importação/publicação em base activa. Fonte aceite conforme decisãoTempo08/10;P038–P043 permanecem funcionais pendentes.
607
608
609
File diff suppressed because one or more lines are too long
@@ -1,11 +1,13 @@
import { useState } from 'react';
import { fundraisingActivities } from '@/lib/iva-fundraising';
import { pharmaAnnexEntries, pharmaAnnexEntry, pharmaAnnexReference } from '@/lib/iva-pharma-annex';
import { emptyProductionTaxOption, type ProductionTaxOption } from '@/lib/iva-production-option';
import { modeloA06Correspondence, newSalesOperation, operationTreatments, recordSales, reuseSales, salesBook, salesCurrent, salesReportRows, saveSalesBook, splitSales, type SalesBook, type SalesOperation } from '@/lib/iva-operations';
export function SimulationOperations({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}) {
const [error,setError]=useState('');
const [reuseOption,setReuseOption]=useState<{rowId:string;sourceId:string}|null>(null);
const [annexSearch,setAnnexSearch]=useState<Record<string,string>>({});
let book:SalesBook;
try{book=salesBook(draft);}catch(cause){return <p role="alert">{String(cause)}</p>;}
const run=(action:()=>void)=>{try{action();setError('');}catch(cause){setError(cause instanceof Error?cause.message:String(cause));}};
@@ -29,6 +31,13 @@ export function SimulationOperations({draft,onChange}:{draft:Record<string,unkno
<label>Representação do preço<select className="block rounded border p-2" value={row.basis} onChange={e=>change(row.id,{basis:e.target.value as SalesOperation['basis']})}><option value="">Ainda desconhecida</option><option value="net">Sem IVA</option><option value="included">IVA incluído</option></select></label>
<label>Tratamento da operação<select className="block rounded border p-2" value={row.treatment} onChange={e=>change(row.id,{treatment:e.target.value,confirmed:[]})}>{operationTreatments.map(t=><option value={t.id} key={t.id}>{t.label}</option>)}</select></label>
</div>
{row.treatment==='pharma_manufacturing_inputs'&&<fieldset className="space-y-2 rounded border p-2"><legend>Bem do Anexo III — edição Lei22/2022</legend>
<p>Escolha a linha pelo código e pela designação. O estabelecimento que transmite deve estar integrado no SNS; o destino hospitalar não substitui essa condição. A selecção não classifica automaticamente uma mercadoria nem confirma a sua utilização.</p>
<label className="block">Pesquisar código ou designação<input value={annexSearch[row.id]??''} onChange={e=>setAnnexSearch({...annexSearch,[row.id]:e.target.value})}/></label>
<label className="block">Linha do Anexo III<select className="block max-w-full rounded border p-2" value={row.pharmaAnnexItem??''} onChange={e=>change(row.id,{pharmaAnnexItem:e.target.value})}><option value="">Ainda por determinar</option>{pharmaAnnexEntries.filter(entry=>entry.id===row.pharmaAnnexItem||`${entry.code} ${entry.label}`.toLocaleLowerCase('pt').includes((annexSearch[row.id]??'').trim().toLocaleLowerCase('pt'))).map(entry=><option key={entry.id} value={entry.id}>{entry.code} — {entry.label} (PDF{entry.pdfPage})</option>)}</select></label>
{row.pharmaAnnexItem&&<p>{pharmaAnnexEntry(row.pharmaAnnexItem)?pharmaAnnexReference(pharmaAnnexEntry(row.pharmaAnnexItem)!):`Escolha guardada não encontrada nesta edição: ${row.pharmaAnnexItem}. Original conservado; seleccione explicitamente a correspondência.`}</p>}
<p>O exemplar repete2912.19.00 em duas linhas com designações diferentes e imprime2935. sem completar a posição. As linhas mantêm identidades próprias; não se inventam dígitos nem se estende a isenção apenas pelo código.</p>
</fieldset>}
{row.treatment.startsWith('fundraising_')&&<fieldset className="space-y-2 rounded border p-2"><legend>Manifestação ocasional — limite anual da entidade</legend><p>O total é declarado para a entidade em todo o ano, incluindo manifestações fora deste dossier. Várias vendas da mesma manifestação não são novas manifestações.</p>
{([['entityReference','Referência da entidade organizadora'],['annualEvents','Total anual de manifestações da entidade, incluindo esta'],['eventNumber','Número desta manifestação no ano']] as const).map(([field,label])=><label className="block" key={field}>{label}<input value={row.fundraiser?.[field]??''} onChange={e=>change(row.id,{fundraiser:{entityReference:'',annualEvents:'',eventNumber:'',activity:'',...row.fundraiser,[field]:e.target.value}})}/></label>)}
<label className="block">Actividade habitual isenta<select value={row.fundraiser?.activity??''} onChange={e=>change(row.id,{fundraiser:{entityReference:'',annualEvents:'',eventNumber:'',...row.fundraiser,activity:e.target.value}})}><option value="">Por identificar</option>{fundraisingActivities.filter(([id])=>row.treatment==='fundraising_nonprofit'?!id.endsWith('_public'):id!=='statutory_membership').map(([id,label])=><option key={id} value={id}>{label}</option>)}</select></label>
+6 -2
View File
@@ -1,5 +1,6 @@
import { acquisitionScope, readAcquisitionStore } from './iva-acquisitions.ts';
import { fundraisingError, type FundraisingContext } from './iva-fundraising.ts';
import { pharmaAnnexEntry, pharmaAnnexReference, pharmaAnnexSource, pharmaAnnexVersion } from './iva-pharma-annex.ts';
import { productionOptionCheck, productionOptionVersion, type ProductionTaxOption } from './iva-production-option.ts';
import { monthlySalesFromDraft, readMonthlyIvaSettings } from './monthly-iva.ts';
import { addFractions, decimalFraction, fraction, fractionLabel, fractionPresentation, type FiscalFraction } from './fiscal-rational.ts';
@@ -55,6 +56,7 @@ const listedGoodsTreatments:OperationTreatment[] = [
['insecticides','Insecticidas','Bem transmitido identificado como insecticida; não qualquer produto químico'],
].map(([id,label,condition])=>({id:`listed_${id}`,label:`Lista legal — ${label}`,field:'05',rate:0,article:'CIVA arts.9(10),19(1)(b)(v), redacção Lei22/2022',source:'Lei22/2022 art.1, PDF2, p.2252(26),9(10); CIVA republicado Lei13/2016, PDF15, p.1426(273),19(1)(b)(v). Âmbito técnico2026/MZN',conditions:[internalOperation,'Transmissão do próprio bem enumerado, identificado; não um serviço autónomo nem extensão por sector, marca ou destino',condition]}));
export const operationTreatments:OperationTreatment[] = [
{id:'pharma_manufacturing_inputs',label:'Bens do Anexo III para fabrico de medicamentos — estabelecimento integrado no SNS',field:'07',rate:0,logicVersion:pharmaAnnexVersion,article:'CIVA arts.9(1)(g),19(1); Lei22/2022 art.3(1)',source:`CIVA republicado Lei13/2016, PDF9, p.1426(267),9(1)(g), e PDF15, p.1426(273),19(1); rectificação BR89/2017, PDF1, p.569; ${pharmaAnnexSource}. Âmbito técnico2026/MZN`,conditions:[internalOperation,'Transmissão efectuada pelo próprio estabelecimento público ou privado identificado, integrado no Serviço Nacional de Saúde; não basta que o adquirente ou destino seja um hospital','Bens a utilizar como matérias-primas, produtos intermédios ou componentes para o fabrico de medicamentos, com utilização/fundamento identificados; não mera venda de produto acabado ou utilização genérica','Bem corresponde cumulativamente ao código e à designação da linha seleccionada no Anexo III; confirmar as especificações aplicáveis sem corrigir ou completar a pauta por suposição']},
...([false,true] as const).map(nonprofit=>({...socialTreatment(`fundraising_${nonprofit?'nonprofit':'public'}`,`Angariação ocasional de fundos — ${nonprofit?'organismo sem finalidade lucrativa':'entidade pública'}`,'h',['Actividade habitual isenta identificada:9(1)(a),9(2)(a/b/c/d/e/g) ou9(3)(a/b), com condições dessa isenção e fundamento identificados','Manifestação ocasional destinada à angariação de fundos em proveito exclusivo da entidade organizadora','Total anual declarado inclui esta manifestação e as realizadas fora deste dossier; não superior a oito no ano'],nonprofit),logicVersion:'fundraising/1',source:'CIVA republicado Lei13/2016, PDF10, p.1426(268),9(2)(h); PDF15, p.1426(273),19(1); Lei22/2022 art.1, PDF1, p.2252(25),9(1–3), e PDF2, p.2252(26),10(1–2). Âmbito técnico2026/MZN'})),
...(['agriculture','forestry','livestock','fishing'] as const).flatMap((kind,index)=>{
const label=['Produção agrícola, avicultura e apicultura','Produção silvícola','Produção pecuária','Pesca'][index],letter=['a','b','c','d'][index];
@@ -110,7 +112,7 @@ export const operationTreatments:OperationTreatment[] = [
{id:'foreign_operation',label:'Operação no estrangeiro — analisar territorialidade',field:null,rate:null,article:'CIVA art.6: localização por natureza da operação; art.19(1)(b)(ii) não determina sozinho a caixa06 do formulário',source:source2016,conditions:[]},
{id:'other',label:'Outra operação / enquadramento ainda desconhecido',field:null,rate:null,article:'Fundamento específico ainda necessário; não presumir taxa ou isenção',source:'Sem fonte operacional determinada para esta linha',conditions:[]},
];
export type SalesOperation = {id:string;period:string;description:string;establishment:string;amount:string;basis:''|'net'|'included';treatment:string;confirmed:number[];evidence:string;sourceAmount:string|null;sourcePeriod:string;sourceCurrency:string;source:string;taxOption?:ProductionTaxOption;fundraiser?:FundraisingContext; splitSource?:{id:string;amount:string|null;period:string;currency:string;basis:string}};
export type SalesOperation = {id:string;period:string;description:string;establishment:string;amount:string;basis:''|'net'|'included';treatment:string;confirmed:number[];evidence:string;sourceAmount:string|null;sourcePeriod:string;sourceCurrency:string;source:string;taxOption?:ProductionTaxOption;fundraiser?:FundraisingContext;pharmaAnnexItem?:string; splitSource?:{id:string;amount:string|null;period:string;currency:string;basis:string}};
export type SalesBook = {currency:string;rows:SalesOperation[];periods:Array<{period:string;complete:boolean}>; result?:SalesResult; history?:SalesResult[]};
export type SalesLineResult = {id:string;field:string|null;net:string|null;vat:string|null;gross:string|null;rate:number|null;status:'calculated'|'exempt'|'indeterminate';reason:string;article:string;source:string;exact?:{net:FiscalFraction;vat:FiscalFraction;gross:FiscalFraction}};
export type SalesResult = {version:string;revision:number;calculatedAt:string;opportunity:string;location:string;currency:string;key:string;inputs:SalesOperation[];rows:SalesLineResult[];periods:Array<{period:string;fields:Record<string,string|null>;exactFields?:Record<string,FiscalFraction|null>;reasons:string[]}>;rounding:string};
@@ -149,7 +151,8 @@ function money(n:bigint):string {return `${n/1000000n}.${(n%1000000n).toString()
function sum(values:Array<string|null>):string|null {const parsed=values.map(amount);return parsed.some(v=>v===null)?null:money((parsed as bigint[]).reduce((a,b)=>a+b,0n));}
export function evaluateSalesOperation(row:SalesOperation,currency:string):SalesLineResult {
const rule=operationTreatments.find(r=>r.id===row.treatment),n=amount(row.amount);
const result:SalesLineResult={id:row.id,field:rule?.field??null,net:null,vat:null,gross:null,rate:rule?.rate??null,status:'indeterminate',reason:'',article:rule?.article??'Tratamento desconhecido',source:rule?.source??'Fonte em falta'};
const annex=row.treatment==='pharma_manufacturing_inputs'?pharmaAnnexEntry(row.pharmaAnnexItem):undefined;
const result:SalesLineResult={id:row.id,field:rule?.field??null,net:null,vat:null,gross:null,rate:rule?.rate??null,status:'indeterminate',reason:'',article:rule?.article??'Tratamento desconhecido',source:(rule?.source??'Fonte em falta')+(annex?`; ${pharmaAnnexReference(annex)}`:'')};
const stop=(reason:string)=>({...result,reason});
if(currency!=='MZN'||row.sourceCurrency!==currency)return stop('Moeda fora de MZN ou divergente da origem; sem conversão silenciosa.');
if(!/^2026-(0[1-9]|1[0-2])$/.test(row.period))return stop('Período fora da cobertura de2026; sem cálculo histórico presumido.');
@@ -158,6 +161,7 @@ export function evaluateSalesOperation(row:SalesOperation,currency:string):Sales
if(!row.description.trim()||!row.establishment.trim())return stop('Indique a operação e o estabelecimento a que pertence; não inferidos da localização do investimento.');
if(rule.conditions.some((_,i)=>!row.confirmed.includes(i))||!row.evidence.trim())return stop('Condições da operação ou fundamento/pressuposto em falta; o sector não prova o tratamento fiscal.');
if(row.sourceAmount!==null&&amount(row.sourceAmount)!==n)return stop('Divergência com o valor reutilizado: conserve a origem e prepare a repartição explicitamente; não substituir silenciosamente.');
if(row.treatment==='pharma_manufacturing_inputs'&&!annex)return stop('Escolha a linha aplicável do Anexo III/2022, com código e designação; um código livre, desconhecido ou de outro anexo não comprova a isenção.');
if(row.treatment==='fundraising_public'||row.treatment==='fundraising_nonprofit'){const error=fundraisingError(row.fundraiser,row.treatment==='fundraising_nonprofit');if(error)return stop(error);}
const option=row.treatment.startsWith('production_')&&row.treatment.endsWith('_opted')?productionOptionCheck(row.taxOption,row.period):{};
if(option.error)return stop(option.error);
+180
View File
@@ -0,0 +1,180 @@
// Transcription of the accepted official exemplar, not a tariff classification service.
// Keep duplicated codes and printed incomplete positions distinct; never infer missing digits.
export const pharmaAnnexVersion='annexIII-lei22-2022/1';
export const pharmaAnnexSource='Lei22/2022, art.3(1), AnexoIII, PDF12–16, p.2252(36)–(40); efeitos01/01/2023';
export const pharmaAnnexPdfSha256='ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53';
export type PharmaAnnexEntry={id:string;code:string;label:string;pdfPage:number;lastPdfPage:number};
export const pharmaAnnexEntries:PharmaAnnexEntry[]=[
{"id":"annexIII-2022-001","code":"1108.11.00","label":"- Amido de trigo","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-002","code":"1108.12.00","label":"- Amido de milho","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-003","code":"1108.19.00","label":"- Outros amidos e féculas","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-004","code":"1301.20.00","label":"- Goma – arábica","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-005","code":"1301.90.00","label":"- Goma – laca; Gomas, resinas, gomas – resinas e oleorresinas (bálsamo, por exemplo), naturais - Outras","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-006","code":"1505.00.00","label":"- Lanolina","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-007","code":"1521.90.00","label":"- Ceras; cera de abelhas; cera de carnaúba; espermacete; ozocerite","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-008","code":"1701.99.00","label":"- Sacarose","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-009","code":"1702.11.00","label":"- Lactose","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-010","code":"1702.19.00","label":"- Lactose mono-hidratada (500 mg)","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-011","code":"1702.30.00","label":"- Glucose","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-012","code":"1702.50.00","label":"- Futose padrão","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-013","code":"2207.10.10","label":"- Álcool etílico para uso hospitalares","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-014","code":"2507.00.00","label":"- Caulino","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-015","code":"2709.00.00","label":"- Óleo Mineral betuminoso","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-016","code":"2806.10.00","label":"- Ácido Clorídrico","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-017","code":"2807.00.00","label":"- Ácido Sulfúrico","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-018","code":"2808.00.00","label":"- Ácido Nítrico","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-019","code":"2809.10.00","label":"- Pentóxido de difósforo","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-020","code":"2809.20.00","label":"- Ácido forfórico","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-021","code":"2810.00.00","label":"- Ácido Bórico","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-022","code":"2811.22.00","label":"- Dióxido de silício","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-023","code":"2811.29.00","label":"- Ácidos inorgânicos e outros componentes oxigenados inorgânicos dos elementos não metálicos - Outros","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-024","code":"2812.90.00","label":"- Halogenetos e oxialogenetos dos elementos não – metálicos - Outros","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-025","code":"2813.90.00","label":"- Sulfuretos dos elementos não-metalicos; trissulfureto de fósforo comercial - Outros","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-026","code":"2815.20.00","label":"- Hidróxido de Potássio","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-027","code":"2815.30.00","label":"- Peróxidos de Sódio ou de Potássio","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-028","code":"2819.90.00","label":"- Óxidos e hidróxidos de crónico - Outros","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-029","code":"2823.00.00","label":"- Óxido de Titânio","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-030","code":"2825.90.00","label":"- Hidrazina e hidroxilamina, e seus sais orgânicos - Outros","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-031","code":"2827.20.00","label":"- Cloreto de cálcio","pdfPage":12,"lastPdfPage":12},
{"id":"annexIII-2022-032","code":"2827.39.00","label":"- Cloretos, oxicloretos e hidroxicloretos, brometos e oxibrometos iodetos e oxiodetos - Outros","pdfPage":12,"lastPdfPage":13},
{"id":"annexIII-2022-033","code":"2827.60.00","label":"- Iodetos e oxidetos","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-034","code":"2829.19.00","label":"- Cloratos e precloratos; bromatos e perbromatos; iodatos e periodatos --Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-035","code":"2829.90.00","label":"- Cloratos e precloratos; bromatos e perbromatos; iodatos e peridatos - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-036","code":"2832.30.00","label":"- Tiossulfatos","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-037","code":"2833.29.00","label":"- Sulfatos de sódio - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-038","code":"2834.29.00","label":"- Nitritos, nitratos - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-039","code":"2835.22.00","label":"- Fosfato sódico monobásico, fosfato sódico dibásico","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-040","code":"2835.24.00","label":"- Fosfato de Potássio Monobásico, fosfato de potássio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-041","code":"2835.25.00","label":"- Hidrogeno-ortofosfato de cálcio (fosfato dicalcico)","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-042","code":"2835.29.00","label":"- Outros fosfatos","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-043","code":"2836.40.00","label":"- Carbonato de Potássio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-044","code":"2836.50.00","label":"-Carbonato de Cálcio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-045","code":"2836.99.00","label":"- Carbonatos; Peroxocarbonatos (percarbonatos); carbonato de amónio comercial que contenha carbonato de amónio - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-046","code":"2837.19.00","label":"- Solução de Cianeto de Potássio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-047","code":"2839.90.00","label":"- Trissilicato de magnésio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-048","code":"2841.50.00","label":"- Cromato de Potássio AR","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-049","code":"2841.61.00","label":"- Permanganato de Potássio; Permanganato de Potássio AR","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-050","code":"2841.70.00","label":"- Solução de Mobibdato de Amónio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-051","code":"2841.80.00","label":"- Tungstato de sódio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-052","code":"2841.90.00","label":"- Piroantimoniato de Potássio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-053","code":"2842.90.00","label":"- Outros sais dos ácidos ou peróxidos inorgânicos","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-054","code":"2843.21.00","label":"- Nitrato de Prata","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-055","code":"2843.29.00","label":"- Cianeto de Potássio; Citrato Cúprico Alcalino TS","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-056","code":"2847.00.00","label":"- Peróxido de Hidrogénio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-057","code":"2901.29.00","label":"- Hidrocarbonetos acíclicos - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-058","code":"2902.11.00","label":"- Ciclohexano","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-059","code":"2902.20.00","label":"- Benzeno","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-060","code":"2902.30.00","label":"- Tolueno","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-061","code":"2902.90.00","label":"- Cloreto de Mitileno; Diclorometano;","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-062","code":"2903.13.00","label":"- Clorofórmio","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-063","code":"2903.14.00","label":"- Tetracloreto de Carbono","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-064","code":"2903.22.00","label":"- Tricloetileno","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-065","code":"2904.91.00","label":"- Hidrocarbonetos cíclicos - Outros","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-066","code":"2905.11.00","label":"- Metanol; Metanol HPLC; Metanol P.A","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-067","code":"2905.12.00","label":"- Álcool Isopropílico; Álcool n-Propílico","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-068","code":"2905.13.00","label":"- Etanol; clorobutanol","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-069","code":"2905.14.00","label":"- Álcool estearílico; álcool cetílico; álcool palmítico","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-070","code":"2905.19.00","label":"- Propranolol Cloridrato (200mg)","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-071","code":"2905.31.00","label":"- Etinoglicol","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-072","code":"2905.32.00","label":"- Propilenoglicol","pdfPage":13,"lastPdfPage":13},
{"id":"annexIII-2022-073","code":"2905.43.00","label":"- Manita ou manitol","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-074","code":"2905.44.00","label":"- D-glucitol (sorbitol)","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-075","code":"2905.45.00","label":"- Glicerina","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-076","code":"2905.49.00","label":"- Alcoois acíclicos e seus derivados halogenados, sulfonados, nitrados ou nitrosados - Outros","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-077","code":"2906.13.00","label":"- Esteróis e inositois","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-078","code":"2906.21.00","label":"- Álcool benzílico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-079","code":"2907.15.00","label":"- 1 – Naftol Ts; 2 -naftol","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-080","code":"2907.19.00","label":"Fénois; fenóis-alcoois - Outros","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-081","code":"2907.29.00","label":"Pelifenois; fénois-alcoois - Outros","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-082","code":"2909.19.00","label":"- Etér Etílico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-083","code":"2909.49.00","label":"- Outros Eteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-084","code":"2912.19.00","label":"- Solução de Formaldeido","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-085","code":"2912.19.00","label":"- Acetaldeíco; Anisaldeído;p-dimetilaminobenzaldeído","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-086","code":"2914.11.00","label":"- Acetona","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-087","code":"2914.13.00","label":"- 4-metilpentan-2-ol","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-088","code":"2915.21.00","label":"- Ácido Acético glacial","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-089","code":"2915.24.00","label":"- Anidrido Acético","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-090","code":"2915.39.00","label":"- Acidos monocarboxilicos acíclicos saturados e seus anidridos, halogenetos, peróxidos e peroxiácidos, seus derivados halogenados, sulfanados, nitrados ou nitrosados - Outros","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-091","code":"2915.50.00","label":"- Ácido propionico, seus sais e seus ésteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-092","code":"2915.70.00","label":"- Ácidos palmíticos, ácido esteárico, seus sais e seus ésteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-093","code":"2915.90.00","label":"- Ácidos monocarboxilicos acíclicos saturados e seus anidridos, halogenetos, peróxidos e perxiácidos; seus derivados halogenados, sulfanados, nitrados ou nitrosados - Outros","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-094","code":"2916.15.00","label":"- Ácido oleico, linoléico, seus sais e seus ésteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-095","code":"2916.31.00","label":"- Ácido benzóico sais e seus ésteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-096","code":"2916.32.00","label":"- Cloreto de benzoílo","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-097","code":"2916.39.00","label":"- Benzoato de sódio","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-098","code":"2917.11.00","label":"- Ácido oxálico; Oxalato de amónia AR","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-099","code":"2917.12.00","label":"- Ácido adípico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-100","code":"2918.11.00","label":"- Ácido láctico, seus sais e seus ésteres","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-101","code":"2918.12.00","label":"- Ácido Tartárico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-102","code":"2918.14.00","label":"- Ácido Cítrico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-103","code":"2918.15.00","label":"- Sais e éstres do ácido cítrico: Citrato de sódio","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-104","code":"2918.16.00","label":"- Ácido Glucónico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-105","code":"2918.19.00","label":"- Tartarato de sódio, ésteres propílico, octílico e dodecílico do ácido gálico","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-106","code":"2918.99.00","label":"- Captopril (200 mg); Captopril","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-107","code":"2921.59.00","label":"- Dietilamina","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-108","code":"2922.12.00","label":"- Dietilamina","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-109","code":"2922.15.00","label":"- Trietanolamina e seus sais","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-110","code":"2922.29.00","label":"- Cloridrato de procaína","pdfPage":14,"lastPdfPage":14},
{"id":"annexIII-2022-111","code":"2922.49.00","label":"- Compostos aminados de funções oxigenadas - Outros","pdfPage":14,"lastPdfPage":15},
{"id":"annexIII-2022-112","code":"2923.90.00","label":"- Sais e Hidróxido de Amónio quatenários - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-113","code":"2924.29.00","label":"- Compostos de função carboxiamida; compostos de funçãoamida do ácido carbónico - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-114","code":"2925.11.00","label":"- Sacarina sódica e seus sais","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-115","code":"2925.19.00","label":"- o – Tolina","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-116","code":"2926.10.00","label":"- Acrilonitrila","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-117","code":"2930.90.00","label":"- Tiocompostos orgânicos - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-118","code":"2932.11.00","label":"- Tetrahidrofurano","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-119","code":"2932.99.00","label":"- Compostos heterocíclicos exclusivamente de heteroátomos de oxigénio - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-120","code":"2933.31.00","label":"- Piridina e seus sais","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-121","code":"2933.39.00","label":"Compostos hetrocíclicos exclusivamente de heteroatomos de azoto - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-122","code":"2933.91.00","label":"- Diazepam; Diazepam padrão; Composto Relacionado A de Diazepam; Composto relacionado B de Diazepam; Nordazepam padrão; Haloperidol (200 mg); Haloperido Composto Relacionado A (10 mg); Haloperidol Composto Relacionado B (10mg)","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-123","code":"2935.","label":"- Sulfonamidas","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-124","code":"2936.24.00","label":"- Ácido Fólico (500 mg) (Vitamina M ou Vitamina Bc); Ácido Fólico (500 mg) Composto relacionado A","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-125","code":"2936.27.00","label":"- Ácido ascórbico, ésteres de ácido ascórbico","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-126","code":"2936.28.00","label":"- Tocoferóis","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-127","code":"2936.29.00","label":"- Niacinamida","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-128","code":"2937.21.00","label":"- Prednison padrão","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-129","code":"2937.23.00","label":"- Progesterona 20 mg","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-130","code":"2939.30.00","label":"- Cafeina e seus sais","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-131","code":"2940.00.00","label":"- Açúcares quimicamente puros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-132","code":"2941.10.00","label":"- Penicilinas e seus derivados","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-133","code":"2941.30.00","label":"- Tetraclinas e seus derivados","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-134","code":"2941.90.00","label":"- Antibióticos - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-135","code":"2942.00.00","label":"- Compostos orgânicos","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-136","code":"3204.11.00","label":"- Corantes dispersos e preparações à base desses corantes","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-137","code":"3206.19.00","label":"- Outras matérias corantes - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-138","code":"3404.90.00","label":"- Cera microcristalina","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-139","code":"3503.00.00","label":"- Gelatina","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-140","code":"3505.10.00","label":"- Amidoglicolato de sódio (glicolato de amido sódico); Goma de amido TS; derivados de amido","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-141","code":"3701.99.00","label":"- Filmes, folhas e laminados: filmes de plástico; filmes de celulose regenerada; folhas ou lâminas de alumínio; folhas ou lâminas de alumínio (laminas ou revestidas com uma camada plástica)","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-142","code":"3901.90.00","label":"- Polietileno ( de baixa, média e alta densidade)","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-143","code":"3904.90.00","label":"- Cloresto de polivinilo (PVP) (com ou sem plastificante)","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-144","code":"3906.90.00","label":"- Polímero acrílico em forma primária - Outros","pdfPage":15,"lastPdfPage":15},
{"id":"annexIII-2022-145","code":"3911.90.00","label":"- Resinas sintéticas","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-146","code":"3912.31.00","label":"- Carboximetilcelulose e seus sais","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-147","code":"3912.90.00","label":"- Celulose e seus derivados - Outros","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-148","code":"3923.30.20","label":"- Embalagens para acondicionamento de medicamentos e produtos","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-149","code":"3926.90.90","label":"- Barricas plásticas, paletes de plástico","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-150","code":"4014.90.00","label":"- Artigos de higiene ou farmácia de borracha vulcanizada não endurecida - Outras","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-151","code":"4821.10.00","label":"- Etiquetas impressas (aprovação, reprovado, quarentena)","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-152","code":"5906.10.00","label":"- Fita gomada","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-153","code":"7010.10.00","label":"- Frascos de vidro, ampolas","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-154","code":"7017.90.00","label":"- Artefactos de vidro para laboratório, higiene e farmácia, mesmo graduados ou calibrados - Outros","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-155","code":"7310.10.00","label":"- Barricas metálicas","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-156","code":"7313.00.00","label":"- Arame farpado de ferro ou aço; Arames ou tiras retorcidos, mesmoi farpado de ferro ou aço, do tipo utinlizado em cercas","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-157","code":"7604.29.00","label":"- Placas de alumínio, ou ligas de alumínio","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-158","code":"7607.19.00","label":"- Placas de alumínio; filmes para fabrico de envelopes, blisters e strips","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-159","code":"7612.90.00","label":"- Recipientes para armazenamento e transporte de líquido","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-160","code":"7616.91.00","label":"- Paletes de alumínio","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-161","code":"8311.90.00","label":"- Outros fios, varetas, tubos, chapas e artefactos semelhantes de metais comuns","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-162","code":"8414.59.00","label":"- Câmaras de fluxo laminar","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-163","code":"8418.50.10","label":"-Refrigeradores, congeladores para usos nos laboratórios para fins medicinais","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-164","code":"8419.89.00","label":"- Estufa de leito fluidizado","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-165","code":"8456.90.00","label":"- Máquina para moldagem de supositórios","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-166","code":"8480.20.00","label":"- Placas de fundo para moldes","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-167","code":"9016.00.00","label":"- Balanças sensíveis e pesos iguais ou inferiores a 5 cg","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-168","code":"9018.39.00","label":"- Sistemas para bolsas de Injectáveis","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-169","code":"9025.19.00","label":"- Outros Termómetros","pdfPage":16,"lastPdfPage":16},
{"id":"annexIII-2022-170","code":"9025.90.00","label":"- Partes e acessórios de instrumentos de medição","pdfPage":16,"lastPdfPage":16}
];
export function pharmaAnnexEntry(id:unknown):PharmaAnnexEntry|undefined {return typeof id==='string'?pharmaAnnexEntries.find(entry=>entry.id===id):undefined;}
export function pharmaAnnexReference(entry:PharmaAnnexEntry):string {return `AnexoIII/2022: ${entry.id}; código ${entry.code}; ${entry.label}; PDF${entry.pdfPage}${entry.lastPdfPage===entry.pdfPage?'':`–${entry.lastPdfPage}`}; ${pharmaAnnexVersion}`;}
@@ -0,0 +1,43 @@
<?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 IvaPharmaInputsDraftTest extends TestCase
{
use DatabaseTransactions;
public function test_selected_annex_rows_round_trip_with_their_own_opportunity(): 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_G2K_INPUT') ?: base_path('outputs/iva-l1-g2-pharma-inputs-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']);
$store = json_decode($recovered['modelo_a_snapshot'], true);
$book = $store['salesOperations']['opportunity:320'];
$this->assertSame('opportunity:320', $book['result']['opportunity']);
$this->assertSame('MZN', $book['result']['currency']);
$this->assertSame('2026-12', $book['result']['periods'][0]['period']);
$this->assertCount(5, $book['result']['rows']);
$this->assertSame('500.00', $book['result']['periods'][0]['fields']['07']);
$this->assertSame('0.00', $book['result']['periods'][0]['fields']['05']);
$this->assertNotSame($book['rows'][1]['pharmaAnnexItem'], $book['rows'][2]['pharmaAnnexItem']);
$this->assertStringContainsString('2912.19.00', $book['result']['rows'][1]['source']);
$this->assertStringContainsString('2912.19.00', $book['result']['rows'][2]['source']);
$this->assertStringContainsString('2935.', $book['result']['rows'][3]['source']);
$this->assertStringContainsString('PDF16', $book['result']['rows'][4]['source']);
$original = json_decode(file_get_contents(base_path('tests/frontend/fixtures/iva-fundraising.json')), true, flags: JSON_THROW_ON_ERROR);
foreach (json_decode($original['modelo_a_snapshot'], true)['salesOperations'] as $key => $value) {
$this->assertSame($value, $store['salesOperations'][$key]);
}
if (getenv('IVA_G2K_RECOVERED')) file_put_contents(getenv('IVA_G2K_RECOVERED'), json_encode($recovered, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE));
}
}
File diff suppressed because one or more lines are too long
+51
View File
@@ -0,0 +1,51 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import fs from 'node:fs';
import {pharmaAnnexEntries,pharmaAnnexEntry,pharmaAnnexVersion} from '../../resources/js/lib/iva-pharma-annex.ts';
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 rule=operationTreatments.find(t=>t.id==='pharma_manufacturing_inputs');
const seed=()=>JSON.parse(fs.readFileSync(new URL('./fixtures/iva-fundraising.json',import.meta.url),'utf8'));
const operation=(entry,i=0)=>({...newSalesOperation(`g2k-${i}`,'2026-12','MZN'),description:`SYNTHETIC QA ${entry.code} ${entry.id}`,establishment:'SYNTHETIC QA estabelecimento transmitente integrado no SNS — Manica',amount:'100',basis:i%2?'included':'net',treatment:rule.id,pharmaAnnexItem:entry.id,confirmed:rule.conditions.map((_,n)=>n),evidence:'SYNTHETIC QA: integração do próprio transmitente no SNS, utilização no fabrico e correspondência código/designação expressamente pressupostas; não é certificação'});
function fixture(){const draft=seed();draft.context_opportunity='opportunity:320';draft.project_title='SYNTHETIC QA — G2K Anexo III';
const entries=[pharmaAnnexEntries[0],...pharmaAnnexEntries.filter(e=>e.code==='2912.19.00'||e.code==='2935.'),pharmaAnnexEntries.at(-1)];
const book=recordSales(draft,{currency:'MZN',rows:entries.map(operation),periods:[{period:'2026-12',complete:true}]});
draft.modelo_a_snapshot=saveSalesBook(draft,book);return {draft,book};}
test('AnexoIII has 170 documentary rows, including two distinct 2912.19.00 entries and printed 2935. position',()=>{
assert.equal(pharmaAnnexEntries.length,170);assert.equal(new Set(pharmaAnnexEntries.map(e=>e.id)).size,170);
assert.equal(new Set(pharmaAnnexEntries.map(e=>e.code)).size,169);
const duplicates=pharmaAnnexEntries.filter(e=>e.code==='2912.19.00');assert.equal(duplicates.length,2);assert.notEqual(duplicates[0].label,duplicates[1].label);
assert.equal(pharmaAnnexEntries.filter(e=>e.code==='2935.').length,1);assert.equal(pharmaAnnexEntry('2935.00.00'),undefined);
assert.equal(pharmaAnnexEntries.find(e=>e.code==='2827.39.00').lastPdfPage,13);assert.equal(pharmaAnnexEntries.find(e=>e.code==='2922.49.00').lastPdfPage,15);
for(const [i,entry] of pharmaAnnexEntries.entries()){
const r=evaluateSalesOperation(operation(entry,i),'MZN');assert.equal(r.status,'exempt');assert.equal(r.field,'07');assert.equal(r.vat,'0.00');assert.equal(r.gross,'100.00');
for(const token of [entry.id,entry.code,entry.label,`PDF${entry.pdfPage}`,pharmaAnnexVersion])assert.ok(r.source.includes(token),token);
}
});
test('P008 requires the transmitting establishment, manufacturing use, exact annex identity and evidence; unknown is not zero',()=>{
const {draft,book}=fixture(),row=book.rows[0];
assert.match(rule.conditions[1],/pelo próprio estabelecimento/);assert.match(rule.conditions[1],/não basta.*adquirente/);
for(const missing of row.confirmed)assert.equal(evaluateSalesOperation({...row,confirmed:row.confirmed.filter(n=>n!==missing)},'MZN').vat,null);
for(const patch of [{pharmaAnnexItem:undefined},{pharmaAnnexItem:''},{pharmaAnnexItem:'1108.11.00'},{pharmaAnnexItem:'annexI-2022-001'},{pharmaAnnexItem:'annexIII-2017-001'},{evidence:''},{establishment:''},{amount:''},{period:'2025-12'},{sourceCurrency:'USD'}])assert.equal(evaluateSalesOperation({...row,...patch},'MZN').vat,null);
assert.equal(evaluateSalesOperation(row,'USD').vat,null);
const unknown=recordSales(draft,{...book,rows:[{...row,pharmaAnnexItem:''}]});assert.equal(unknown.result.periods[0].fields['07'],null);
assert.deepEqual(unknown.history.at(-1),book.result);
});
test('P008 keeps its row identity, report and selected opportunity through recovery; eleven delivered books remain current without recalculation',()=>{
const {draft,book}=fixture(),original=seed(),old=JSON.parse(original.modelo_a_snapshot).salesOperations;
const recovered=JSON.parse(JSON.stringify(draft)),store=JSON.parse(recovered.modelo_a_snapshot).salesOperations;
assert.equal(Object.keys(old).length,11);
for(const [id,value] of Object.entries(old)){assert.deepEqual(store[id],value);assert.equal(salesCurrent({...recovered,context_opportunity:id},value),true,id);}
assert.equal(salesCurrent(recovered,salesBook(recovered)),true);
const report=JSON.stringify(createProjectDossierReport(recovered,{selectedSections:new Set(['finance'])}));
for(const token of ['500.00','opportunity:320','Manica','2026-12','MZN','AnexoIII/2022',pharmaAnnexVersion,...book.rows.map(r=>r.pharmaAnnexItem)])assert.ok(report.includes(token),token);
assert.equal(report.includes('fundraising_public'),false);assert.equal(report.includes('production_forestry_opted'),false);
assert.deepEqual(recovered.selection_labels,original.selection_labels);assert.equal(recovered.currency,original.currency);
const duplicates=pharmaAnnexEntries.filter(e=>e.code==='2912.19.00');
const changed={...book,rows:book.rows.map(r=>r.pharmaAnnexItem===duplicates[0].id?{...r,pharmaAnnexItem:duplicates[1].id}:r)};
assert.equal(salesCurrent(draft,changed),false);assert.deepEqual(changed.result,book.result);
});
if(process.env.IVA_G2K_OUT)fs.writeFileSync(process.env.IVA_G2K_OUT,JSON.stringify(fixture().draft,null,2));