Compare commits

..
24 changed files with 2173 additions and 139 deletions
@@ -825,3 +825,98 @@ Para cada nova regra: condição satisfeita, negativa, informação em falta, pe
Reutilizado o inventário autorizado de **8143ficheiros**, sem nova varredura de pastas. Para delimitação foram consultados os originais CIRPC/alterações já arquivados, a Lei4/2009 local e a compilação oficial [APIEX — Legislação de Investimentos em Moçambique](https://pt.apiex.gov.mz/wp-content/uploads/2025/02/LEGISLACAO-DE-INVESTIMENTOS-EM-MOCAMBIQUE.pdf), que reúne Lei8/2023, Decreto8/2024 e CBF4/2009. Disponibilidade, situação documental/jurídica e uso no cálculo continuam estados independentes. O acesso actual à cópia CBF supera a indisponibilidade assinalada em notas antigas; não activa regra nem apaga a nota histórica. Artigos, páginas, hashes e limites no recibo. A compilação não dispensa o período/alterações de cada tratamento, nem cria validação jurídica genérica adicional.
**Código por implementar em L7:** qualificação e persistência específicas; efeitos segregados; regras das famílias acima, por parcelas; conciliação sem duplicação; relatório/exportação correspondente. **Documentação por caso:** estatuto/reconhecimento ou enquadramento individual quando a fonte o exige; identificação de parcela/limite/cronologia; norma sectorial ainda sem correspondência; edição/campo de transporte afectado. Cada uma conserva exemplo e condição de retoma na linha correspondente. Não é necessário resolver todos os documentos para começar o primeiro incremento independente. L6 operacional não elimina este desenvolvimento; L7 delimitado não é L7 implementado; L8 conserva a liquidação final.
## 26/10/2026 — L7: qualificação, despesas autónomas e casos compatíveis em QA
**QA, sem instalação.** Base instalada preservada `5aaf1a56`; delimitação `d37fffb2`; ramo `codex/irpc-l7-common-autonomous-qa-20261026`, fotografia opcional `IRPC-normal-adjustments/10`. L6 continua operacional no âmbito demonstrado, com os cinco grupos de código e cinco documentais preservados. A implementação abaixo acrescenta apenas os tratamentos demonstrados; não conclui L7 nem o IRPC. Saldo final, retenções, pagamentos e aplicação anual de créditos permanecem em L8.
**Qualificação comum executável:** reutiliza sujeito/NUIT, âmbito, período, origem da oportunidade/dossier, sector e território; guarda condições, prova, fonte/artigo e período por tratamento. «Informação em falta», «ausência declarada», «não aplicável/condição negativa» e «calculado» têm resultados distintos. Desconhecido não vira zero. Período incompatível, identidade por reconciliar ou contradição afectam só o resultado dependente. A localização não escolhe taxa nem activa benefício. Os snapshots de origem ficam internos; o relatório apresenta contexto legível e as condições documentadas.
**Despesas61(4):** cada parcela aponta para uma linha `undocumented` do mapa36(1)g de L6, com acréscimo integral já calculado. Montante, documento e linha são reutilizados; L7 não introduz outro acréscimo nem outra despesa. A classificação legal e incidência são declaradas com prova própria; falta de anexo não classifica uma despesa. O imposto autónomo usa35% apenas nos casos qualificados. Duplicação da referência, parcela não correspondida, ausência contraditória ou informação insuficiente deixam o imposto reconciliado indeterminado; as parcelas conhecidas permanecem discriminadas. Condição negativa documentada conserva o ajustamentoL6 e não aplica imposto autónomo à parcela.
**Cooperativas12/14:** agrárias, artesanato ou culturais, residentes, com base ordinária integralmente elegível e ausência documentada de rendimentos sujeitos a retenção, aplicam redução de50% à taxa geral32%, ou16%. Não depende de seleccionar um sector semelhante. A qualificação especial pode coexistir com a opção «outro tratamento» da colectaL6: não exige fingir que a taxa reduzida é regime geral. Parcela mista, rendimentos retidos, outra entidade ou ausência contraditória conservam pendência própria; não recebem redução global presumida. O imposto autónomo de despesas não é reduzido por esta taxa.
**CBF16:** reutiliza identificadores e valores dos activosL6 suportados; imóvel novo do projecto ou máquinas industriais/agro-industriais das categorias correspondidas, com enquadramentoCBF3/9 e reconhecimento10 quando exigido (ou excepção identificada). Recorte inicial: primeiro exercício anual civil2026, método constante pela taxa normal máxima da tabela, activo desde01/01/2026, custo histórico novo, sem quotas anteriores/saída e sem cumulação de outros benefícios. Incrementa a taxa normal em50% e reutiliza limites de contabilização/saldo fiscal. Deduz apenas a diferença entre o mapa normal e o acelerado, sem alterar o activo de origem, os documentos ou os saldos oficiais. Quotas constantes gerais e demais cálculosL6 conservam o comportamento anterior quandoL7 está ausente.
| Caso sintético recuperado da API QA | Lucro/base e colecta de referênciaL6 | EfeitoL7 demonstrado | Resultado e limite |
| --- | --- | --- | --- |
| Despesa100 já acrescida36g | Lucro/base3230;colecta1033,60MZN | Novo ajustamento ao lucro0;imposto autónomo35 | Colecta combinada1068,60MZN;saldo finalL8indeterminado |
| Classificação da mesma despesa em falta | Lucro/base3230;colecta1033,60MZN preservados | Imposto autónomo indeterminado | Colecta combinada indeterminada;sem perda dos cálculos independentes |
| Condição negativa documentada na parcela | Ajustamento36g100 preservado | Parcela não aplicável;imposto autónomo0 justificado | Não confunde condição negativa com informação em falta |
| Ausência declarada de despesas autónomas | Lucro/base3130;colecta1001,60MZN | Ausência com suporte;imposto autónomo0 | Ausência contraditória com despesa36g fica pendente |
| Cooperativa integralmente abrangida | Base3130;colecta geral1001,60MZN | Taxa16%;colecta500,80MZN | Base/proveitos não alterados;sem retenções/créditos abatidos |
| Máquina industrial existente:base1000,taxa10%,quota contabilística120 | Quota normal100;lucro/base6260;colecta2003,20MZN | Quota acelerada150,mas dedução limitada120;diferença adicional20 | Lucro/base6240;colecta1996,80MZN;sem deduzir50 nem150 outra vez |
**Cálculo → gravação → recuperação → relatório:** fotografia10 opcional no mesmo livro/snapshot, chave com entradas/contexto e histórico imutável anterior. SemL7, a fotografia9 aceite e a sua chave/totais permanecem iguais. Recalcular não acumula imposto nem duplica o acréscimo. HTML e dossier financeiro mostram referênciaL6, efeitosL7, parcelas autónomas, fonte, condições, período e limitações; recuperação e download demonstrados no componente real. Uma mudança de origem/entradas torna a fotografia anterior histórica; não altera o registo anterior. M20/M22 conservam a preparaçãoL6 de referência: **este incremento não transporta efeitosL7 para campos oficiais por aproximação**, nem resolve as divergências documentais existentes.
**Provas novas:** Wayfinder `--with-form` gerou routes/actions pelo wrapper QA; TypeScript e build QA passaram. Dezanove testes dirigidos novos passaram, incluindo comparação exacta com a fotografia9 aceite, duplicação, período curto, opção especial de cooperativa, ausência contraditória, dados em falta e contexto apresentado sem despejar snapshots internos. API privada:1teste/108asserções, `simulator_fiscal_delta_20261021_test`,127.0.0.1:55441, transacção com rollback e guarda de identidade/base; seis casos recuperados com plano/livro/históricos idênticos. UI do componente real: alteração de classificação, informação em falta, ausência, cooperativa mista, cumulação pendente, gravação/recuperação local e exportação; sem erros de página. A prova local é distinta da API. Não houve testes/escrita no activo nem repetição das suites funcionais aceites de L3, ISPC, câmbio ou L5/L6.
**Entrega agrupada preparada:** qualificação + despesas autónomas, cooperativa integralmente elegível e amortizaçãoCBF16 no recorte acima. Despesa autónoma e cooperativa também foram demonstradas juntas:parcela35 sem redução,colecta sobre a base516,80 e combinada551,80MZN no exemplo de base3230. Isto não autoriza cumulação cooperativa+CBF16: essa combinação mantém resultado dependente indeterminado. A futura instalação segue o procedimento Git existente, com backup/restauro fresco e conferência do delta; não foi executada nesta passagem.
**SaldoL7 na mesma matriz:**
| Natureza | Ainda fora da cobertura / exemplo | Condição concreta de retoma |
| --- | --- | --- |
| Código | Despesa autónoma fora de linha36g calculada ou parcela ainda não segregada | Implementar origem/segregação correspondente e prova da incidência;não copiar montante para uma segunda despesa |
| Código | Cooperativa com actividade abrangida e outra não abrangida,ou rendimento sujeito a retenção | Segregar proveitos/custos/base e aplicar o tratamento apenas à parcela elegível;L5 conserva a retenção |
| Código | CBF16 em imóvel reabilitado,outra categoria,quota inferior à máxima,método degressivo,duodécimos,quotas anteriores ou exercício posterior | Corresponder regra e cronologia respectivas e reutilizar o activo/quotas existentes;pendênciaL6 limita apenas o activo dependente |
| Código/documento por caso | Cooperativa+CBF16 ou outro benefício positivo a cumular | Identificar compatibilidade,ordem e limites específicos;implementar a combinação,sem presumir soma de benefícios |
| Código | Mais-valias61-A,demais isenções/deduçõesCBF17–19,regimes sectoriais/territoriais e operações especiais | Implementar a família/parcelas já delimitadas na secção anterior;período e fonte específicos,sem nova pesquisa transversal |
| Documento por caso | Estatuto/título/excepçãoCBF ou prova das condições em falta;endereçoZEE sem estatuto | Juntar o elemento que a disposição exige ou registar condição negativa;localização isolada permanece insuficiente |
| Transporte/documento | CampoM20/M22 para efeitoL7,edição divergente ou representação não correspondida | Correspondência do campo/edição e regra de representação demonstradas;preservar o cálculo independente exacto |
| ÂmbitoL8 | Direito potencial ao créditoCBF15,aplicação anual de créditos,retenções,pagamentos e saldo final | Executar o mecanismo próprioL8;nenhuma dedução/compensação anual é presumida neste lote |
Fontes reutilizadas: inventário autorizado8143ficheiros; originaisCIRPC/alterações e CBF/compilaçãoAPIEX já identificados na delimitação,com hashes conservados. Sem activação por consulta ou revalidação jurídica genérica. Recibo: `docs/investmoz/simulations/irpc-l7-common-qa-20261026.json`. Provas locais: `outputs/irpc-l7-common/`; reprodução dirigida: `node --test tests/frontend/irpc-special.test.mjs`, `php tools/irpc-special-qa.php routes`, `php tools/irpc-special-qa.php test`, `tsc --noEmit`, build com `INVESTMOZ_QA_BUILD=1`.
## 26/10/2026 — preparação da entrega L7 e preservação do main concorrente
A entrega do âmbito QA `ab2ff2fd` integra o `main` concorrente `a2122dc3`, sem substituir as alterações de apresentação/navegação. Os seis ficheiros de execução L7 conservam exactamente o código QA;os oito ficheiros concorrentes conservam exactamente o código do main. Reutilizadas as provas19testes/API108/UI/tipos/build de L7. O conflito documental foi resolvido recuperando586linhas de histórico do manual que tinham sido removidas no merge concorrente,sem apagar a sua notaV2-01 no CSV. As3555linhas mantêm-se,com o único delta fiscal emAUD-SIM-INT02. O registo de instalação só será actualizado após backup/restauro fresco,conferência do destino e conclusão da entrega Git;esta nota não a antecipa.
## 26/10/2026 — primeira entrega agrupada L7 instalada pelo Git
Instalada `e07f89da3d59d06aa1b8c50c22a478b7b167bfdd` (integração do código QA `ab2ff2fdbcbe6fb94f03e4bc4cc7ccbd647d94fc` com o main concorrente`a2122dc3`),com `5aaf1a56f9d928331364fcc8b0d1528e51dba327` preservado como versão anterior. Os seis ficheiros de execução L7 são exactamente os da prova QA aceite;as sete alterações concorrentes de apresentação/navegação e o respectivo teste foram preservados. Recuperadas586linhas de histórico do manual removidas no merge concorrente;notaV2-01 conservada,sem alterar o seu conteúdo.
Backup fresco `2026-10-26T10:55:59Z`;restauro isolado sem rede/55441 verificou174tabelas por contagem/checksum e369ficheiros/configuração. Conferidos13ficheiros de execução do delta,50protegidos e31originais. Schema,roles/grants e permissões mantêm-se;172tabelas de negócio iguais ao backup. Cache/sessões reconciliadas por eventos operacionais e acessos públicos,sem inferir perda por RLS. A versão activa e a anterior foram preservadas durante o arquivo conferido de dependências antigas para recuperar espaço;nenhum dado,original ou backup foi eliminado.
Revisão/manifest público,marcadoresL7/L6/câmbio,assets e simuladorHTTP200 conferidos. Procedimento Git concluído;provas funcionais aceites19testes/API108/UI/tipos/build reutilizadas. Os controlos automáticos obrigatórios da instalação ficaram registados no recibo,sem nova ronda manual dos casos aceites. Sem migrações,importações,recálculo de históricos ou escrita privada sintética no activo.
Disponíveis apenas qualificação e tratamentos demonstrados:despesas61(4) sobre36g já ajustado,cooperativas12 integralmente abrangidas eCBF16 no recorte documentado. L6 permanece operacional no âmbito aceite;as suas pendências condicionam só dependentes. L7/IRPC não estão integralmente concluídos;localização não concede benefício;saldo final permaneceL8. O estado anterior deQA sem instalação é histórico. Recibo:`docs/investmoz/simulations/irpc-l7-common-delivery-20261026.json`.
## 26/10/2026 — saldo concreto de L7 após a primeira entrega agrupada
O âmbito demonstrado compreende qualificação comum, imposto autónomo61(4) sobre parcelas36g já calculadas emL6, cooperativas12 integralmente abrangidas e amortizaçãoCBF16 nos activos/período/método expressamente suportados. L7 permanece parcial. Este saldo distingue implementação de prova documental por caso; não cria outra matriz nem exige revalidação genérica das fontes aceites. L6 mantém o estado operacional delimitado e as suas pendências; só condiciona tratamentos que efectivamente dependam delas.
### Código ainda por implementar
| Tratamento / caso fora da cobertura | Exemplo | Condição concreta de retoma |
| --- | --- | --- |
| Despesas autónomas fora de parcela36g calculada e segregações adicionais | Despesa100 com apenas60 correspondidos no mapa de origem,ou encargo não incluído no resultado de partida | Implementar origem/parcela e reconciliação próprias,documentar incidência61(4) e impedir nova contabilização/acréscimo da mesma despesa. O ramo já entregue36g não é reaberto. |
| Cooperativas com rendimentos mistos/retidos;demais isenções por natureza da entidade,CIRPC9–14 | Cooperativa com actividade agrária e serviços não abrangidos;associação com rendimentos comerciais acessórios | Segregar proveitos,custos e base elegível e implementar o artigo específico. Não reduzir a base inteira nem estender a redução às retençõesL5. |
| ExtensõesCBF16 e combinações de benefícios | Imóvel reabilitado,método degressivo,quota inferior à máxima,duodécimos,quotas anteriores,ano posterior,cooperativa+CBF16 | Corresponder a regra temporal/método/contabilização e a compatibilidade/ordem/limite da combinação;reutilizar activo e quotas. Tabela ou casoL6 em falta impede apenas o activo dependente. |
| Mais-valias autónomas61-A e operações especiais | Ganho100 já incluído no resultado em2026;entrada de activos/fusão;perda transferida de outra sociedade | Implementar apuramento/parcela e reconciliação com resultadoL6,sem dupla incidência ou compensação de perdas presumida;para operações,aplicar54–56/41-A e preservar valores históricos. |
| Deduções/majoraçõesCBF17–19 e crédito potencialCBF15 | Formação sem ramo/base de limite;investimento novo com activos elegíveis e excluídos | Implementar elegibilidade,base,limite,ordem,janela temporal e não cumulação. CBF15 emL7 delimita direito/origem/crédito potencial;utilização anual,limitação por créditos/saldos e liquidação ficam emL8. |
| Regimes sectoriais/territoriais e disposições especiais | Projecto emZEE sem tratamentoIRPC correspondido;actividade mineira/petrolífera com regime próprio | Implementar a disposição/versão/período aplicáveis ao projecto e à parcela (CBF20–48 ou diploma específico). Endereço/código sectorial só identifica candidato;benefício aduaneiro não se transforma em benefícioIRPC. |
| Transporte de efeitosL7 paraM20/M22 | Imposto autónomo ou redução calculados mas sem campo/edição correspondente | Implementar apenas a correspondência demonstrada e a representação aplicável;conservar os montantes exactos e a preparaçãoL6 de referência,sem campo/taxa provisórios. |
### Dependências documentais que condicionam apenas o caso afectado
| Elemento em falta / dúvida concreta | Exemplo | Condição de retoma |
| --- | --- | --- |
| Classificação/incidência,parcela e período da operação | Há uma despesa36g e falta qualificar61(4);ou há actividade elegível e outra não abrangida | Associar prova/declaração da natureza e parcela ao exercício correcto. Informação em falta continua indeterminada;condição negativa e ausência declarada têm suporte próprio. Não inferir pela falta de anexo. |
| Estatuto e reconhecimento exigidos pela disposição | Endereço numaZEE sem estatuto do projecto;CBF16 sem instrumento10 ou norma de excepção | Juntar o elemento concreto exigido ou documentar a condição negativa/excepção aplicável. Não pedir aprovador ou parecer jurídico genérico adicional. |
| Norma/período/compatibilidade específicos ainda não correspondidos | Redução com termo31/12/2025 pretendida em2026;cumulação cooperativa+CBF16 | Disposição de vigência/prorrogação efectiva ou correspondência da combinação e seus limites. Sem informação nova,não repetir pesquisa transversal;prosseguir com os restantes casos. |
| Edição,campo ou representação do formulário | EfectoL7 com campoM20/M22 não identificado ou fracção sem regra de representação | Identificar exemplar/edição,instrução/campo e forma de representar o valor;limitar a pendência ao transporte afectado. O cálculo independente mantém-se disponível. |
**Limites conservados:** localização não concede benefícios automaticamente;benefício desconhecido não é zero;colecta normal,L7 e imposto autónomo permanecem discriminados. Retenções,pagamentos,aplicação anual de créditos e saldo final a pagar/recuperar continuam emL8. As provas aceites não são invalidadas por esta lista nem por uma dúvida documental num caso independente.
## 26/10/2026 — reconciliação do estado servido L7 e capacidade do instalador
Conferência autenticada por leitura em `2026-10-26T13:56:51.412248+02:00` (Africa/Johannesburg):o portal,o registo do instalador e o main actual coincidem em `e07f89da3d59d06aa1b8c50c22a478b7b167bfdd`. **L7 já está instalado no âmbito demonstrado**,com origemQA`ab2ff2fd`;o estado «ainda emQA,sem instalação» é histórico/desactualizado. A instalação terminou em26/10/2026 às13:02:35 locais;backup anterior às12:55:59 e restauro174tabelas/369ficheiros permanecem comprovados pelo recibo de entrega. Nesta passagem,o dump e o arquivo de ficheiros ainda coincidem com os hashes desse backup e a prova de restauro refere o mesmo dump. Não foi apresentado um novo backup/restauro como executado,nem repetida a instalação da revisão já activa.
**Partição do instalador e backup:**`/dev/md2 / ext4`;release,state,backup,tmp eDocker no mesmo dispositivo. Livres5.52GiB e21448231inodes de29089792. O código do instalador mantém o limiar5GiB;os ficheiros do backup observado ocupam0.164GiB. A leitura satisfaz5GiB+um backup desse tamanho,com margem0.35GiB. A release actual tem28674ficheiros e2503directórios sem seguir links,como referência de escala,não um novo limite arbitrário de inodes. Futuras entregas devem voltar a medir a capacidade imediatamente antes da operação;estes números não garantem uma carga futura diferente. Nenhuma limpeza local/remota foi executada;SGF TEMPO não foi afectado.
**Só o delta L7:**seis hashes de código correspondem à provaQA;revisão/manifest,sete marcadoresL7,quatroassets e entrada do simuladorHTTP200 conferidos. Reutilizadas as provas19testes/API108/UI/tipos/build e as provas anteriores de preservaçãoL6/L3/ISPC/câmbio;sem nova ronda funcional,escrita privada sintética,migração ou importação. A revisão activa e a anterior permanecem preservadas.
**Próximo conjunto delimitado para implementaçãoQA:CBF16 com duodécimos.** Reutilizar activos,tabela/taxa normal máxima,método constante,qualificaçãoCBF e periodizaçãoL6 existentes. Primeiro caso:exercício anual civil2026 com entrada em uso durante o ano;imóvel novo do projecto ou máquina industrial/agro-industrial já suportada;sem quotas anteriores,saída ou cumulação de outros benefícios. Ligar a quota mensalL6 ao incrementoCBF16,limitando ao contabilizado/saldo fiscal e mostrando apenas a diferença adicional. Demonstrar condição satisfeita,negativa,informação em falta e ausência declarada,cálculo→gravação→recuperação→relatório,efeitos no lucro/base/colecta e conservação dos históricos. Este conjunto está apenas delimitado:não é novo cálculo instalado.
Degressivo,reabilitados/usados/reavaliados,quotas anteriores e cumulação cooperativa+CBF16 continuam nos casos próprios. O saldo anterior de sete grupos de código e quatro dependências documentais permanece na mesma matriz,com exemplos/condições de retoma;nenhuma pendência foi apagada. Documento individual em falta limita só o activo/caso dependente. Localização não concede benefício. **L6 operacional delimitado;L7 parcial;retenções,pagamentos,créditos anuais e saldo final emL8.** Recibo:`docs/investmoz/simulations/irpc-l7-server-state-20261026.json`.
@@ -0,0 +1,585 @@
{
"status": "installed_first_grouped_L7_demonstrated_scope",
"installed": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0
},
"QA_candidate": "ab2ff2fdbcbe6fb94f03e4bc4cc7ccbd647d94fc",
"integration_candidate": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"previous_main": "a2122dc34cc9d3e8b64938c3d6b31cc36f336154",
"previous_installed": "5aaf1a56f9d928331364fcc8b0d1528e51dba327",
"authorization": "Tempo:disponibilizar entrega agrupadaL7 peloGit,backup/restauro fresco,conferência do delta,preservarL6/provas aceites e apresentar saldo concreto",
"backup": {
"stage": "/var/backups/investmoz-irpc-l7-common-delivery-20261026/backup",
"created_at": "2026-10-26T10:55:59Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "a3d46de6c10b37bd6f211125686da8c489f879ab243f082e7b72a397638901f9",
"files_sha256": "409d378ce59ca3d82e39cbf44f139114a839e1aa56457755316a2fecdd7e5b07",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l7_restore_20261026",
"port": 55441,
"source_dump_sha256": "a3d46de6c10b37bd6f211125686da8c489f879ab243f082e7b72a397638901f9",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"installed": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 13,
"preserved_L3_ISPC_FX_runtime_files_verified": 50,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "63f3ceed97ce2f40106530ef6eb6e083"
},
"after": {
"rows": 106,
"checksum": "38aa09dc08f13ff12ac1e71dbae22d0b"
}
},
"sessions": {
"before": {
"rows": 11,
"checksum": "823228a21cb8173718f6010a9aaa319a"
},
"after": {
"rows": 14,
"checksum": "1529684ad387db4b9aaa40ac775ebe74"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions_before": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected"
},
"schema_permissions_after": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart;requestthrottle;identical home-sector cached value with refreshed expiry(HomeController remember10min);no deletedcache",
"sessions": "anonymous sessions from delivery user-agent or exactUA/time correlated with nginx public request;deleted sessions individually expired beyond configured lifetime,normal database session garbage collection(config/session lottery2/100)",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "8d6ea77eb4b34d86d207362d583cfa8bf2880b907becd9b00398964482c6b4bd",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true,
"same_value_home_cache_expiry_refresh": false
},
{
"key_sha256": "2f251473865d14b953236ab95b1521764754d76abd79b58ca7d38c96dfe2fab1",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true,
"same_value_home_cache_expiry_refresh": false
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false,
"same_value_home_cache_expiry_refresh": false
}
]
},
"sessions": {
"before_rows": 11,
"after_rows": 14,
"changes": [
{
"key_sha256": "cd8c2106a4f4ab7802317e6602c26cfa4cf82a23a86f67a0abbc27fbd82edfb8",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "a89dca10cb8a95f4451ff60eeefe7ac3cd7751b779b0bf97a7e5f5b894f9b115",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "7fb2119013f872a5e4dd70952cc896a4ac8291134e02362bd60805eb77e9587a",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"branch": "main",
"built_at": "2026-10-26T11:02:32.435267+00:00",
"manifest_sha256": "d78a1bdb503c10849f5ea8d8879753653c2c2fc22f6182f6d68ec9f6adf635b5"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-normal-adjustments/10": [
"assets/project-dossier-KEyrPtc6.js"
],
"Preparar qualificação L7": [
"assets/services-BSj1SuMk.js"
],
"Despesas — imposto autónomo": [
"assets/project-dossier-KEyrPtc6.js"
],
"Cooperativa — redução da taxa": [
"assets/project-dossier-KEyrPtc6.js"
],
"Amortizações aceleradas": [
"assets/services-BSj1SuMk.js",
"assets/project-dossier-KEyrPtc6.js"
],
"novo ajustamento ao lucro:": [
"assets/project-dossier-KEyrPtc6.js"
],
"colecta combinada:": [
"assets/project-dossier-KEyrPtc6.js"
],
"Saldo final — âmbito L8": [
"assets/project-dossier-KEyrPtc6.js"
],
"Reutilizar selecção cambial": [
"assets/services-BSj1SuMk.js"
]
},
"assets": [
{
"file": "assets/project-dossier-document-BRdhvWgC.js",
"status": 200,
"sha256": "5b1de561be552259de776a2dbaf4b49909a3edd2647fec7c296a96054c929a9f"
},
{
"file": "assets/services-BSj1SuMk.js",
"status": 200,
"sha256": "ea1a3812cbced72f4df115e8e379ae6d2307e97b2152d288b1c80d357f03f78b"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/project-dossier-KEyrPtc6.js",
"status": 200,
"sha256": "b6ae250a30b5030a6e40e7dfb140a3335ce6d5bc16835098d3d7c5828fc526c5"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-ByAQSjfI.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"pipeline": {
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"installed": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0
},
"latest_report": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"e07f89da3d59d06aa1b8c50c22a478b7b167bfdd"
],
"finished_at": "2026-10-26T11:02:35.885260+00:00"
},
"log_file": "1793012270105316629.log",
"summaries": [
"OK (1 test, 3106 assertions)",
"built in 33.69s",
"OK (59 tests, 317 assertions)",
"# tests 1007",
"# pass 1007",
"# fail 0"
],
"log_bytes": 287128
},
"concurrent_main_reconciliation": {
"QA_candidate": "ab2ff2fdbcbe6fb94f03e4bc4cc7ccbd647d94fc",
"concurrent_main": "a2122dc34cc9d3e8b64938c3d6b31cc36f336154",
"installed_baseline": "5aaf1a56f9d928331364fcc8b0d1528e51dba327",
"runtime_QA_files_exact": [
"resources/js/lib/irpc-special.ts",
"resources/js/components/simulation-irpc-special.tsx",
"resources/js/lib/irpc-normal.ts",
"resources/js/lib/irpc-normal-depreciation.ts",
"resources/js/components/simulation-irpc-normal.tsx",
"resources/js/lib/project-dossier-report.ts"
],
"concurrent_files_preserved": {
"resources/js/components/portal-hero.tsx": "0ebe2c3e2ae2615d966d050864699a90dac2fef36ebfc174aa1059b83db9a514",
"resources/js/components/tempo-brand.tsx": "27c01d317ec59c9a4ddb2a184c0a8a9427fcf92d34a916060287d07226364d02",
"resources/js/layouts/portal-navigation.tsx": "f1f66b645035f56c9bcc7fbc8c2983e84eb29ae3ecb99461e3963a7deefbaaa6",
"resources/js/lib/portal-navigation.ts": "12aad264eeb5cebe7c9bf467391c611f58d1b84cc9d5fd30db983ba640e25951",
"resources/js/pages/PortalInvestidor.tsx": "d418f960f82ae0d054acfe094047bc80a16f7b418506f054e6d7da07edf6ef00",
"resources/js/pages/investment/shared.tsx": "00098334435de3bb5c7b13608c0e53c63a4bdee7d9cdf07f24b3aec54441f05e",
"resources/js/pages/portal/why-invest.tsx": "3917efa7b0d33fe8fe6e4562c3b9e2f53200b9e07807cd29bade328f8e5ae7e2",
"tests/frontend/portal-navigation.test.mjs": "518c7e1de6fb1b385caffe39914e2905bf8f561d938f0527561156602a0e3098"
},
"CSV_concurrent_V2_01_preserved": true,
"removed_manual_history_lines_restored": 586,
"resolution": "main changed only by removing586tail lines from the manual;candidate manual retained in full;CSV auto-merge preserved V2-01 and changed only fiscal rowAUD-SIM-INT02",
"new_functional_round": false,
"accepted_QA_proofs_reused": {
"new_frontend_tests": 19,
"API_tests": 1,
"API_assertions": 108,
"API_database": "simulator_fiscal_delta_20261021_test",
"API_host": "127.0.0.1",
"API_port": 55441,
"API_transaction_rollback": true,
"QA_identity_guard": true,
"Wayfinder_generated_with_form": true,
"typescript_noEmit": true,
"QA_build": true,
"API_recovered_to_HTML_and_financial_dossier_cases": 6,
"UI": {
"actualComponent": true,
"expenseL6Addback100Autonomous35": true,
"missingClassificationDoesNotEraseNormalProfit": true,
"absenceExplicit": true,
"cooperative16MixedCaseBlockedOnly": true,
"acceleratedQuota150LimitedToAccounted120": true,
"netAdditionalDeduction20": true,
"cumulationMissingExplicit": true,
"saveRecoveryDownload": true,
"finalBalanceL8Unknown": true,
"errors": []
},
"old_functional_suites_repeated": false,
"building_and_lower_optional_quota_cases": true
}
},
"dependency_archiving": {
"status": "dependencies_archived_and_verified",
"versions": 8,
"free_before": 4349009920,
"free_after": 6454341632,
"receipt": "/var/backups/investmoz-build-dependencies-irpc-l7-common-20261026/receipt.json",
"protected": [
"/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"/var/www/investmoz-homologacao/releases/56475acb2f39e58cb51664913f7fb499f58eb7ab-694b3932"
],
"active_or_previous_release_modified": false,
"source_data_backups_deleted": 0
},
"accepted_QA_proofs_reused": {
"new_frontend_tests": 19,
"API_tests": 1,
"API_assertions": 108,
"API_database": "simulator_fiscal_delta_20261021_test",
"API_host": "127.0.0.1",
"API_port": 55441,
"API_transaction_rollback": true,
"QA_identity_guard": true,
"Wayfinder_generated_with_form": true,
"typescript_noEmit": true,
"QA_build": true,
"API_recovered_to_HTML_and_financial_dossier_cases": 6,
"UI": {
"actualComponent": true,
"expenseL6Addback100Autonomous35": true,
"missingClassificationDoesNotEraseNormalProfit": true,
"absenceExplicit": true,
"cooperative16MixedCaseBlockedOnly": true,
"acceleratedQuota150LimitedToAccounted120": true,
"netAdditionalDeduction20": true,
"cumulationMissingExplicit": true,
"saveRecoveryDownload": true,
"finalBalanceL8Unknown": true,
"errors": []
},
"old_functional_suites_repeated": false,
"building_and_lower_optional_quota_cases": true
},
"source_inventory_reused": {
"files_reused": 8143,
"broad_search_repeated": false,
"receipt": "irpc-l7-scope-20261026.json",
"sources": [
{
"id": "CIRPC",
"title": "Lei34/2007",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\Lei-34-2007-BR52.pdf",
"bytes": 1676884,
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"references": "PDF5/p768(59):12,14,15; PDF15–16:54–56; PDF17/p768(71):61",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "IRPC-2026",
"title": "Lei12/2025",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\BR-248-I-Suplemento-1-2025.pdf",
"bytes": 440018,
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"references": "PDF18–20; PDF20:art2/61-A,art3,art6; vigência01/01/2026",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "IRPC-2022",
"title": "Lei20/2022",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\BR252-I-Serie-2022-Lei20-PESOE.pdf",
"bytes": 17966640,
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"references": "PDF1/p2731:61(2), termo31/12/2025",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "CBF-local",
"title": "Lei4/2009",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\CBF-Lei4-2009-APIEX.pdf",
"bytes": 10998765,
"sha256": "4231a5b6783e603cedb98992f3e93ecaf1c1d5be341b093560cf2fdd0845b0dc",
"references": "Original local disponível; scan sem extracção textual útil; cotejo textual pela compilação oficial",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false,
"authorised_original": "\\\\Mac\\Home\\Documents\\TEMPO\\Portal Tempo\\Legislacao\\Apiex\\3.-Lei-no4-2009-de-12-de-Janeiro-Codigo-dos-Beneficios-Fiscais.pdf"
},
{
"id": "APIEX",
"title": "Compilação oficial APIEX",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\APIEX-legislacao-investimentos-2025.pdf",
"bytes": 6467655,
"sha256": "ba1e9eaabfec5d0c4cb2d9f2444a6860f7a90f222034764197829be402d408ed",
"references": "pp8–32:Lei8/2023; pp36–59:Decreto8/2024; pp64–92:CBF4/2009; p68:9/10;p71–74:15–19",
"official_url": "https://pt.apiex.gov.mz/wp-content/uploads/2025/02/LEGISLACAO-DE-INVESTIMENTOS-EM-MOCAMBIQUE.pdf",
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "RCBF",
"title": "Decreto56/2009",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\Decreto56-2009-BR40.pdf",
"bytes": 422005,
"sha256": "6ea1b8d93daed48c6d590481d874010fa1708211d8f27c319dc9a31328456017",
"references": "Procedimento já cotejado em iva-l1-p084-p085-model-i1-cotejo-20261024.json; não estende isenções IVA a IRPC",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
}
],
"document_consultation_activates_calculation": false
},
"L6_operational_demonstrated_scope_preserved": true,
"L6_pending_code_and_documentation_preserved": true,
"L7_integrally_complete": false,
"IRPC_integrally_complete": false,
"new_private_synthetic_writes_on_active": 0,
"location_grants_benefit": false,
"L8_retentions_payments_annual_credit_application_final_balance_separate": true,
"remaining_scope": {
"implementation": [
"61(4) sources/partial segregation outside calculated36g",
"cooperative mixed/withheld income and other entity exemptions9–14",
"CBF16 other assets/methods/optional lower quota/periods/prior quotas and combinations",
"61-A capital gains and special operations54–56/41-A",
"CBF17–19 deductions/magnifications andCBF15 potential credit origin/eligibility",
"sector/territory and specific special regimes",
"L7 M20/M22 official transport"
],
"documentary_case_dependencies": [
"nature/incidence/parcel and correct period",
"individual statute/title/recognition or applicable exception only where required",
"specific norm/validity/compatibility/order/limit not corresponded",
"affected form edition/field/representation"
],
"examples_and_resume_conditions": "same consolidated matrix and manual section:saldo concreto de L7 após a primeira entrega agrupada"
},
"evidence": {
"backup.txt": "dac1a5cddac111160d64f4f34184f999cb40655b210582b9a18dbef20aedd8d0",
"baseline.txt": "6e4bf2e80c29cc3c81d14c3da9f44e1ef3d576b0eb25f9c7ecb85f060c15b196",
"compact-dependencies.txt": "a2385728e917cc20008da8b8144ff57a1bcbe3a1a352848c548b11bdf38fbbf0",
"concurrent-main-reconciliation.json": "8a6aefa957e2b28905f89dca161de53bcffdc9dba2575e9f76efb13ac80a6c16",
"installed-protected.txt": "e2fc267572cf8c29ee15e4efa524679843377766d19456ccba4e9187b7c55a21",
"installed-public-delta.json": "557cbdc9ec7db9b0eb6865d0998c83a9c4a957ee041ba1bce0e54cd2df4ee3cb",
"installed-public.txt": "4efa54256c1de8af63f80f0ff245f529cb581746f165a1299d7389ffd8047ee9",
"integration.txt": "c320a8d33ea33e1f70a291b7da2fa4934658b2f87fc9a26a9521325e23cfac7d",
"manifest-served.json": "d78a1bdb503c10849f5ea8d8879753653c2c2fc22f6182f6d68ec9f6adf635b5",
"operational-delta.txt": "18793b0013b52e87ad088317b49ef3ef31e582dfb073500fa29a5822e237f61c",
"preflight-ready.txt": "ffe2dfba440adebbd45ba72336d56668735f4916d3ae5385a4d750c5775a6a04",
"preflight.txt": "6bf42bb982a7e5807123569ba9a4951bd639132b628965586b7ed60f36b5f0ea",
"preparation.json": "46c078247bb3b68f2aabdb9aa5c0e40bf648dbc07e467933ce82d749b9741a00",
"process-progress.txt": "721a9cf3e8b3892122dabe8b05e8c377b097d94ed0123b7135dcf83c53a40cd6",
"progress-2.txt": "df6ae7b7f2e49c9da3ffbe12c0de6746a191f51dcf30428a93a3db4693c7972b",
"progress-3.txt": "de4fa512b1e124d6c48c34eec14ab50fb66ebb718b49c0fd039e6a148598688d",
"progress-4.txt": "de4fa512b1e124d6c48c34eec14ab50fb66ebb718b49c0fd039e6a148598688d",
"restore.txt": "fcf1cbf5a6de6c0ac9172c3b5acd39c7c0438f950a2297be5f84964268ef4c24",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status-before.txt": "290e99722a17dabbeb4bb609b2c3df423357dd1e34b3cc6f4e45cd64e758c797",
"status-final.txt": "3814636ae1e3d45f6da832b42b3a9215503598bc20c0c080b3ab5181a074bea0",
"status-progress-1.txt": "b289c9824a293d6b97db770712ce92e65c714fe72f22e0410ef6447b655d47d6"
}
}
@@ -0,0 +1,570 @@
{
"status": "L7_common_qualification_autonomous_expenses_cooperative_acceleration_QA_prepared_not_installed",
"recorded_date": "2026-10-26",
"installed_baseline": "5aaf1a56f9d928331364fcc8b0d1528e51dba327",
"scope_baseline": "d37fffb2d2eacef6300f1c81fc29993178532f35",
"branch": "codex/irpc-l7-common-autonomous-qa-20261026",
"version": "IRPC-normal-adjustments/10",
"installed": false,
"L6_operational_scope_preserved": true,
"IRPC_integrally_complete": false,
"runtime_delta": {
"resources/js/lib/irpc-special.ts": "5d261cdb54506bd892fa49776bb53a20600e62e64a4c180ef26cdcdb8b6a3806",
"resources/js/components/simulation-irpc-special.tsx": "9ccd89e46703f9dd14c1110459b22673623a19bd652d137f40ec83e0f7c223db",
"resources/js/lib/irpc-normal.ts": "7e63e7e5928a90c5305fd1fca49db883fec32666381ee99ae6fa4b06c711d9a7",
"resources/js/lib/irpc-normal-depreciation.ts": "00ba22e449b23e570bfbbf3895bd334029a16f938d5a5ff999ca67b4318f58c3",
"resources/js/components/simulation-irpc-normal.tsx": "e01e54dee4cd2555a8a27ed77512cf220056b5899ea9dacbaaae6d4063ce2d42",
"resources/js/lib/project-dossier-report.ts": "cba66c88391da83b4fdb345a9570eca5ae83979cbbd508eb44b53995d812718d"
},
"cases_recovered": {
"expense": {
"L6_reference": {
"taxableProfit": {
"numerator": "3230",
"denominator": "1"
},
"taxableBase": {
"numerator": "3230",
"denominator": "1"
},
"colecta": {
"numerator": "5168",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "3230",
"denominator": "1"
},
"L7_base": {
"numerator": "3230",
"denominator": "1"
},
"L7_colecta": {
"numerator": "5168",
"denominator": "5"
},
"autonomous_tax": {
"numerator": "35",
"denominator": "1"
},
"combined_colecta": {
"numerator": "5343",
"denominator": "5"
},
"expense_status": "calculated",
"cooperative_status": "absent",
"acceleration_status": "absent",
"additional_depreciation_deduction": {
"numerator": "0",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
},
"missing": {
"L6_reference": {
"taxableProfit": {
"numerator": "3230",
"denominator": "1"
},
"taxableBase": {
"numerator": "3230",
"denominator": "1"
},
"colecta": {
"numerator": "5168",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "3230",
"denominator": "1"
},
"L7_base": {
"numerator": "3230",
"denominator": "1"
},
"L7_colecta": {
"numerator": "5168",
"denominator": "5"
},
"autonomous_tax": null,
"combined_colecta": null,
"expense_status": "indeterminate",
"cooperative_status": "absent",
"acceleration_status": "absent",
"additional_depreciation_deduction": {
"numerator": "0",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
},
"negative": {
"L6_reference": {
"taxableProfit": {
"numerator": "3230",
"denominator": "1"
},
"taxableBase": {
"numerator": "3230",
"denominator": "1"
},
"colecta": {
"numerator": "5168",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "3230",
"denominator": "1"
},
"L7_base": {
"numerator": "3230",
"denominator": "1"
},
"L7_colecta": {
"numerator": "5168",
"denominator": "5"
},
"autonomous_tax": {
"numerator": "0",
"denominator": "1"
},
"combined_colecta": {
"numerator": "5168",
"denominator": "5"
},
"expense_status": "calculated",
"cooperative_status": "absent",
"acceleration_status": "absent",
"additional_depreciation_deduction": {
"numerator": "0",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
},
"absent": {
"L6_reference": {
"taxableProfit": {
"numerator": "3130",
"denominator": "1"
},
"taxableBase": {
"numerator": "3130",
"denominator": "1"
},
"colecta": {
"numerator": "5008",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "3130",
"denominator": "1"
},
"L7_base": {
"numerator": "3130",
"denominator": "1"
},
"L7_colecta": {
"numerator": "5008",
"denominator": "5"
},
"autonomous_tax": {
"numerator": "0",
"denominator": "1"
},
"combined_colecta": {
"numerator": "5008",
"denominator": "5"
},
"expense_status": "absent",
"cooperative_status": "absent",
"acceleration_status": "absent",
"additional_depreciation_deduction": {
"numerator": "0",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
},
"cooperative": {
"L6_reference": {
"taxableProfit": {
"numerator": "3130",
"denominator": "1"
},
"taxableBase": {
"numerator": "3130",
"denominator": "1"
},
"colecta": {
"numerator": "5008",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "3130",
"denominator": "1"
},
"L7_base": {
"numerator": "3130",
"denominator": "1"
},
"L7_colecta": {
"numerator": "2504",
"denominator": "5"
},
"autonomous_tax": {
"numerator": "0",
"denominator": "1"
},
"combined_colecta": {
"numerator": "2504",
"denominator": "5"
},
"expense_status": "absent",
"cooperative_status": "calculated",
"acceleration_status": "absent",
"additional_depreciation_deduction": {
"numerator": "0",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
},
"acceleration": {
"L6_reference": {
"taxableProfit": {
"numerator": "6260",
"denominator": "1"
},
"taxableBase": {
"numerator": "6260",
"denominator": "1"
},
"colecta": {
"numerator": "10016",
"denominator": "5"
}
},
"L7_profit": {
"numerator": "6240",
"denominator": "1"
},
"L7_base": {
"numerator": "6240",
"denominator": "1"
},
"L7_colecta": {
"numerator": "9984",
"denominator": "5"
},
"autonomous_tax": {
"numerator": "0",
"denominator": "1"
},
"combined_colecta": {
"numerator": "9984",
"denominator": "5"
},
"expense_status": "absent",
"cooperative_status": "absent",
"acceleration_status": "calculated",
"additional_depreciation_deduction": {
"numerator": "20",
"denominator": "1"
},
"history_versions": [
"IRPC-normal-adjustments/1",
"IRPC-normal-adjustments/2",
"IRPC-normal-adjustments/3",
"IRPC-normal-adjustments/4",
"IRPC-normal-adjustments/5",
"IRPC-normal-adjustments/6",
"IRPC-normal-adjustments/7",
"IRPC-normal-adjustments/8",
"IRPC-normal-adjustments/9"
],
"final_balance": {
"scope": "L8",
"payable": null,
"recoverable": null
}
}
},
"source_inventory": {
"files_reused": 8143,
"broad_search_repeated": false,
"receipt": "irpc-l7-scope-20261026.json",
"sources": [
{
"id": "CIRPC",
"title": "Lei34/2007",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\Lei-34-2007-BR52.pdf",
"bytes": 1676884,
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"references": "PDF5/p768(59):12,14,15; PDF15–16:54–56; PDF17/p768(71):61",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "IRPC-2026",
"title": "Lei12/2025",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\BR-248-I-Suplemento-1-2025.pdf",
"bytes": 440018,
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"references": "PDF18–20; PDF20:art2/61-A,art3,art6; vigência01/01/2026",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "IRPC-2022",
"title": "Lei20/2022",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\docs\\investmoz\\simulations\\source-archive\\BR252-I-Serie-2022-Lei20-PESOE.pdf",
"bytes": 17966640,
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"references": "PDF1/p2731:61(2), termo31/12/2025",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "CBF-local",
"title": "Lei4/2009",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\CBF-Lei4-2009-APIEX.pdf",
"bytes": 10998765,
"sha256": "4231a5b6783e603cedb98992f3e93ecaf1c1d5be341b093560cf2fdd0845b0dc",
"references": "Original local disponível; scan sem extracção textual útil; cotejo textual pela compilação oficial",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false,
"authorised_original": "\\\\Mac\\Home\\Documents\\TEMPO\\Portal Tempo\\Legislacao\\Apiex\\3.-Lei-no4-2009-de-12-de-Janeiro-Codigo-dos-Beneficios-Fiscais.pdf"
},
{
"id": "APIEX",
"title": "Compilação oficial APIEX",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\APIEX-legislacao-investimentos-2025.pdf",
"bytes": 6467655,
"sha256": "ba1e9eaabfec5d0c4cb2d9f2444a6860f7a90f222034764197829be402d408ed",
"references": "pp8–32:Lei8/2023; pp36–59:Decreto8/2024; pp64–92:CBF4/2009; p68:9/10;p71–74:15–19",
"official_url": "https://pt.apiex.gov.mz/wp-content/uploads/2025/02/LEGISLACAO-DE-INVESTIMENTOS-EM-MOCAMBIQUE.pdf",
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
},
{
"id": "RCBF",
"title": "Decreto56/2009",
"exemplar": "C:\\laragon\\www\\portal-investidor-irpc-l7-scope-20261026\\outputs\\irpc-l7-scope\\Decreto56-2009-BR40.pdf",
"bytes": 422005,
"sha256": "6ea1b8d93daed48c6d590481d874010fa1708211d8f27c319dc9a31328456017",
"references": "Procedimento já cotejado em iva-l1-p084-p085-model-i1-cotejo-20261024.json; não estende isenções IVA a IRPC",
"official_url": null,
"available_for_consultation": true,
"documentary_status": "official_source_accepted; applicability/version/period_per_treatment",
"new_calculation_activation": false
}
],
"document_consultation_activates_calculation": false
},
"coverage": {
"optional_input_backward_compatible": true,
"accepted_version9_current_key_and_result_unchanged_without_L7": true,
"expense_source": "calculated36(1)g schedule ID;full amount reused;no parallel amount",
"expense_rate": "35/100",
"expense_additional_profit_adjustment": "0",
"cooperative_rate": "32/100 × 1/2 =16/100;eligible ordinary base only",
"accelerated_rate": "normal maximum table rate ×3/2;lower optional quota not covered;first full civil2026,new supported asset,prior quotas zero",
"accelerated_deduction": "min calculated quota/accounted eligible amount/fiscal remaining balance;only difference over normal map",
"mixed_cases": "cooperative+autonomous expense demonstrated;cooperative+CBF16 not supported",
"context": "reuses documented sector/territory/provenance;no benefit by location alone;raw snapshots not dumped in report",
"states": [
"information_missing",
"declared_absence",
"not_applicable_or_negative_condition",
"calculated"
],
"report": "same normalReportRows/HTML and financial project dossier;L6 reference separated from L7 effects",
"final_settlement": "not calculated;L8"
},
"pending": {
"code": [
"autonomous expenses outside already-calculated36g parcel",
"mixed cooperative income/withheld parcels",
"CBF16 rehabilitated/other categories/lower optional quota/methods/months/prior quotas/later years",
"specific benefit combinations and cumulation",
"61-A capital gains and other previously delimited treatment families",
"L7 official form transport"
],
"documents_per_case": [
"individual status/title/exception and qualification proof when required by applicable norm",
"parcel/limit/order/cumulation/chronology not evidenced",
"affected form field/edition/representation correspondence"
],
"resume_conditions": "same existing matrix/manual L7 QA section;no blanket validation or repeated transversal research",
"L6_pending_unchanged": true,
"L8_annual_credit_application_retentions_payments_final_balance_separate": true
},
"checks": {
"new_frontend_tests": 19,
"API_tests": 1,
"API_assertions": 108,
"API_database": "simulator_fiscal_delta_20261021_test",
"API_host": "127.0.0.1",
"API_port": 55441,
"API_transaction_rollback": true,
"QA_identity_guard": true,
"Wayfinder_generated_with_form": true,
"typescript_noEmit": true,
"QA_build": true,
"API_recovered_to_HTML_and_financial_dossier_cases": 6,
"UI": {
"actualComponent": true,
"expenseL6Addback100Autonomous35": true,
"missingClassificationDoesNotEraseNormalProfit": true,
"absenceExplicit": true,
"cooperative16MixedCaseBlockedOnly": true,
"acceleratedQuota150LimitedToAccounted120": true,
"netAdditionalDeduction20": true,
"cumulationMissingExplicit": true,
"saveRecoveryDownload": true,
"finalBalanceL8Unknown": true,
"errors": []
},
"old_functional_suites_repeated": false,
"building_and_lower_optional_quota_cases": true
},
"preservation": {
"baseline": "d37fffb2d2eacef6300f1c81fc29993178532f35",
"files_compared": 662,
"only_existing_changed": [
"resources/js/lib/irpc-normal-depreciation.ts",
"resources/js/lib/irpc-normal.ts",
"resources/js/lib/project-dossier-report.ts"
],
"protected_code_schema_config_routes_contract_files": 576,
"originals": {
"docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973",
"docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b",
"docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c",
"docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57",
"docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063",
"docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee",
"docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5",
"docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358",
"docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5",
"docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb",
"docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8",
"docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be",
"docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c",
"docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b",
"docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56",
"docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4",
"docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a",
"docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76",
"docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d",
"docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899",
"docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee",
"docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53",
"docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e",
"docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121",
"docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d",
"docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d",
"docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
},
"active_writes": 0,
"migrations": 0,
"permission_changes": false
},
"evidence_directory": "outputs/irpc-l7-common",
"delivery": {
"prepared_only": true,
"Git_branch_isolated": true,
"active_installation": false,
"fresh_backup_restore_and_delta_check_required_at_future_installation": true
}
}
@@ -0,0 +1,270 @@
{
"status": "L7_installed_reconfirmed_not_reinstalled",
"checked_at_UTC": "2026-10-26T11:56:51.412248+00:00",
"checked_at_Africa_Johannesburg": "2026-10-26T13:56:51.412248+02:00",
"main": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"QA_origin": "ab2ff2fdbcbe6fb94f03e4bc4cc7ccbd647d94fc",
"installed_commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"previous_delivery_receipt": "irpc-l7-common-delivery-20261026.json",
"server_read_only": {
"checked_at_UTC": "2026-10-26T11:56:51.412248+00:00",
"read_only": true,
"installed": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0
},
"release_revision": {
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"branch": "main",
"built_at": "2026-10-26T11:02:32.435267+00:00",
"manifest_sha256": "d78a1bdb503c10849f5ea8d8879753653c2c2fc22f6182f6d68ec9f6adf635b5"
},
"latest_report": {
"status": "installed",
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"release": "/var/www/investmoz-homologacao/releases/e07f89da3d59d06aa1b8c50c22a478b7b167bfdd-6b82c3f2",
"previous_release": "/var/www/investmoz-homologacao/releases/5aaf1a56f9d928331364fcc8b0d1528e51dba327-c1543f3e",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"e07f89da3d59d06aa1b8c50c22a478b7b167bfdd"
],
"finished_at": "2026-10-26T11:02:35.885260+00:00"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"volumes": [
{
"path": "/var/www/investmoz-homologacao/releases",
"mount": "/dev/md2 / ext4",
"device": 2306,
"total_bytes": 467909804032,
"available_bytes": 5922545664,
"total_inodes": 29089792,
"available_inodes": 21448231
},
{
"path": "/var/lib/investmoz-deploy",
"mount": "/dev/md2 / ext4",
"device": 2306,
"total_bytes": 467909804032,
"available_bytes": 5922545664,
"total_inodes": 29089792,
"available_inodes": 21448231
},
{
"path": "/var/backups",
"mount": "/dev/md2 / ext4",
"device": 2306,
"total_bytes": 467909804032,
"available_bytes": 5922545664,
"total_inodes": 29089792,
"available_inodes": 21448231
},
{
"path": "/tmp",
"mount": "/dev/md2 / ext4",
"device": 2306,
"total_bytes": 467909804032,
"available_bytes": 5922545664,
"total_inodes": 29089792,
"available_inodes": 21448231
},
{
"path": "/var/lib/docker",
"mount": "/dev/md2 / ext4",
"device": 2306,
"total_bytes": 467909804032,
"available_bytes": 5922545664,
"total_inodes": 29089792,
"available_inodes": 21448231
}
],
"existing_pipeline_space_guard_excerpt": [
" self.releases.mkdir(parents=True,exist_ok=True)",
" if shutil.disk_usage(self.releases).free < 5 * 1024**3:",
" raise RuntimeError('Insufficient free space for an isolated build; active release preserved')",
" release=self.releases/(target+'-'+uuid.uuid4().hex[:8]);release.mkdir(mode=0o750)"
],
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604",
"L7_delta_hashes_match": {
"resources/js/components/simulation-irpc-normal.tsx": true,
"resources/js/components/simulation-irpc-special.tsx": true,
"resources/js/lib/irpc-normal-depreciation.ts": true,
"resources/js/lib/irpc-normal.ts": true,
"resources/js/lib/irpc-special.ts": true,
"resources/js/lib/project-dossier-report.ts": true
},
"installed_release_nonlinked_files": 28674,
"installed_release_nonlinked_directories": 2503,
"inode_requirement_note": "Current release file/directory counts are an observed reference,not a guarantee for another build;no new inode threshold introduced.",
"prior_installation_backup": {
"created_at": "2026-10-26T10:55:59Z",
"tables": 174,
"files": 369,
"dump_sha256": "a3d46de6c10b37bd6f211125686da8c489f879ab243f082e7b72a397638901f9",
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l7_restore_20261026",
"port": 55441,
"source_dump_sha256": "a3d46de6c10b37bd6f211125686da8c489f879ab243f082e7b72a397638901f9",
"active_database_writes": 0
},
"files_present": {
"database.dump": {
"present": true,
"bytes": 22880589
},
"files-before.tar.gz": {
"present": true,
"bytes": 153036740
},
"backup-receipt.json": {
"present": true,
"bytes": 94539
},
"restore-receipt.json": {
"present": true,
"bytes": 269
}
}
},
"new_backup_or_restore_executed": false,
"deployment_executed": false,
"cleanup_executed": false,
"active_data_writes": 0
},
"capacity_assessment": {
"mount": "/dev/md2 / ext4",
"existing_pipeline_guard_bytes": 5368709120,
"available_bytes": 5922545664,
"available_inodes": 21448231,
"total_inodes": 29089792,
"same_partition_for_release_state_backup_tmp_docker": true,
"observed_existing_backup_files_bytes": 176012137,
"available_minus_guard_and_one_observed_backup_bytes": 377824407,
"existing_space_guard_plus_observed_backup_satisfied": true,
"inode_reference_files_plus_directories": 31177,
"inode_note": "Available21million vs31thousand entries in current nonlinked release;no new arbitrary threshold or guarantee for changed future payload",
"new_deployment_needed": false
},
"existing_backup_integrity": {
"backup_created_at": "2026-10-26T10:55:59Z",
"existing_dump_hash_matches": true,
"existing_files_archive_hash_matches": true,
"accepted_restore_proof_matches_same_dump": true,
"restored_tables": 174,
"new_backup_or_restore_executed": false,
"active_writes": 0
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "e07f89da3d59d06aa1b8c50c22a478b7b167bfdd",
"branch": "main",
"built_at": "2026-10-26T11:02:32.435267+00:00",
"manifest_sha256": "d78a1bdb503c10849f5ea8d8879753653c2c2fc22f6182f6d68ec9f6adf635b5"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-normal-adjustments/10": [
"assets/project-dossier-KEyrPtc6.js"
],
"Preparar qualificação L7": [
"assets/services-BSj1SuMk.js"
],
"Despesas — imposto autónomo": [
"assets/project-dossier-KEyrPtc6.js"
],
"Cooperativa — redução da taxa": [
"assets/project-dossier-KEyrPtc6.js"
],
"Amortizações aceleradas": [
"assets/project-dossier-KEyrPtc6.js",
"assets/services-BSj1SuMk.js"
],
"novo ajustamento ao lucro:": [
"assets/project-dossier-KEyrPtc6.js"
],
"colecta combinada:": [
"assets/project-dossier-KEyrPtc6.js"
]
},
"assets": [
{
"file": "assets/project-dossier-KEyrPtc6.js",
"status": 200,
"sha256": "b6ae250a30b5030a6e40e7dfb140a3335ce6d5bc16835098d3d7c5828fc526c5"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/services-BSj1SuMk.js",
"status": 200,
"sha256": "ea1a3812cbced72f4df115e8e379ae6d2307e97b2152d288b1c80d357f03f78b"
},
{
"file": "assets/project-dossier-document-BRdhvWgC.js",
"status": 200,
"sha256": "5b1de561be552259de776a2dbaf4b49909a3edd2647fec7c296a96054c929a9f"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-ByAQSjfI.js",
"synthetic_private_writes": 0,
"method": "Read-only L7 revision/manifest/compiled delta/simulator entry;accepted functional proofs reused"
},
"accepted_proofs_reused": {
"QA_frontend_tests": 19,
"QA_API_assertions": 108,
"QA_UI_types_build": true,
"prior_installation_backup_restore_tables": 174,
"prior_installation_files": 369,
"prior_preservation_runtime_files": 50,
"prior_originals": 31,
"new_functional_round": false
},
"next_compatible_QA_scope": {
"status": "delimited_for_next_QA_not_implemented",
"treatment": "CBF16 constant-method depreciation by monthly fractions for supported new assets entering service during2026",
"reuse": [
"existing asset IDs/classification and maximum normal catalogue rates",
"L6 monthly timing/financial source and normal reference result",
"existing qualification/source/title/provenance and versioned book"
],
"first_case": "Civil annual2026,new supported industrial/agroindustrial machine or new project building entering service during the year;documented CBF eligibility,no previous quotas/no other benefits",
"acceptance": [
"normal vs accelerated quota and accounted/fiscal balance caps",
"additional effect only,without second deduction or changes to original asset/history",
"conditions true,false,missing and declared absence",
"calculation-save-recover-report with profit/base/colecta effects and final L8 balance unknown"
],
"out_of_scope": [
"declining method",
"rehabilitated/used/revalued assets",
"recovery of previous quotas",
"cooperative+CBF16 or other benefit combinations",
"unmapped official form fields"
],
"resume_condition": "Link already-demonstrated L6 monthly timing to qualified CBF16 rate increment,retain exact values/caps and prove only new effects in isolated QA;missing project evidence affects that asset only"
},
"remaining_L7_groups_preserved": {
"implementation_groups": 7,
"documentary_case_dependencies": 4,
"section": "saldo concreto de L7 após a primeira entrega agrupada"
},
"L6_operational_scope_and_pending_preserved": true,
"L7_integrally_complete": false,
"L8_final_settlement_separate": true,
"local_cleanup": false,
"SGF_affected": false,
"new_backup_restore_or_installation": false
}
@@ -2523,7 +2523,7 @@ As estimativas são **horas de trabalho técnico**, não calendário nem mediç
| L4 — ISPC: elegibilidade e apuramento | Campos de enquadramento e motor genérico | Regime/actividade/volume elegível, opções/exclusões, escalões/taxas aplicáveis, mínimo, trimestre e retenções específicas; comparação só entre regimes admissíveis | Vendas por actividade, custos, NUIT, natureza jurídica e residência confirmada | Lei9/2025 e regulamentação/período; distinguir receita anual, trimestre e excesso | 40–64 h |
| L5 — retenções IRPC e guias | Documentos de compras/vendas e guia M/39 como exemplar | Rendimento pago/recebido, entidade que retém, residente/não residente/EP, evento temporal, excepções e casos digitais/e-money; guia e comprovativo ligados à operação | Contrapartes, facturas, pagamentos, período, moeda, oportunidade | Artigos aplicáveis por rendimento, taxa/convenção se invocada; corrigir remissões do exemplar. Sem submissão electrónica AT presumida | 32–56 h |
| L6 — IRPC anual: regime normal | Disponível5aaf1a56:percurso normal demonstrado atécolecta,períodos/moedas e preparação parcialM20/M22 | Operacional no âmbito demonstrado por decisãoTempo26/10;limitações explícitas;5grupos código+5documentais preservados;sem conclusão integral | Plano financeiro,dados comuns,activos/livros e histórico;retenções/pagamentos/créditos anuaisL8 | Pendências bloqueiam só os casos dependentes;L7/L8 próprios | Estimativa inicial48–80h;saldo não reestimado |
| L7 — IRPC: tratamentos específicos | Delimitação26/10 e fontes/contexto existentes;sem novo tratamento implementado | Qualificação e efeitos por parcela:autónomas61(4)/61-A,entidades/cooperativas12,CBF15–19,sector/território e operações especiais;ver secção L7 | L6/contexto herdado,despesas,activos e relações documentadas;sem benefício por localização isolada | Condições,fonte/versão,período,limite/cumulação e efeito por caso;crédito potencialL7/aplicação anualL8 | Estimativa inicial48–80h;sem reestimativa |
| L7 — IRPC: tratamentos específicos | e07f89da instalado,reconfirmado26/10:main/revisão/delta6QAab2ff2fd coincidem | L7parcial;7grupos código/4documentais preservados. PróximoQA:CBF16 com duodécimos,activo novo suportado,método constante eano civil2026 | Reutilizar qualificação,activos/taxas eperiodizaçãoL6;sem benefício por localização | Provar só novos efeitos eguarda/recuperação/relatório;limites contabilístico/fiscal;sem repetir instalação;L8 separado | Estimativa inicial48–80h;saldo não reestimado |
| L8 — IRPC: liquidação e pagamentos | Parcelas L5–L7 e formulários originais | PPC/PEC, deduções/créditos, dupla tributação quando aplicável, saldo anual a pagar/recuperar; calendário e reconciliação com pagamentos | Retenções, colecta, saldos anteriores, pagamentos/comprovativos | Base anterior para PPC/PEC, regras de limitação/transporte; não usar cinco anos ou compensação automática sem cotejo específico | 32–56 h |
| L9 — INSS: contribuição social | Massa salarial agregada e referência TCO3%+4% | Trabalhadores, remuneração/base contributiva, exclusões, empregador/trabalhador, TCO/TCP, declaração e encargos por período | Equipa/custos, entidade e calendário; cadastro de pessoa partilhado com L10 | Regulamento e alterações aplicáveis, natureza do vínculo; confirmar base antes da taxa. Contribuição social, distinta dos impostos | 24–40 h |
| L10 — IRPS: retenção mensal e líquido | Entrada IRPS, custos salariais e escalões anuais documentais | Tabela mensal própria, remunerações/benefícios, situação pessoal relevante, retenção, salário líquido e contribuição ligada a L9 | Mesmo trabalhador/folha salarial, pagamentos e retenções | Tabela mensal do período, residência e condições familiares necessárias; não dividir escalões anuais por12 | 40–64 h |
@@ -6342,3 +6342,98 @@ Para cada nova regra: condição satisfeita, negativa, informação em falta, pe
Reutilizado o inventário autorizado de **8143ficheiros**, sem nova varredura de pastas. Para delimitação foram consultados os originais CIRPC/alterações já arquivados, a Lei4/2009 local e a compilação oficial [APIEX — Legislação de Investimentos em Moçambique](https://pt.apiex.gov.mz/wp-content/uploads/2025/02/LEGISLACAO-DE-INVESTIMENTOS-EM-MOCAMBIQUE.pdf), que reúne Lei8/2023, Decreto8/2024 e CBF4/2009. Disponibilidade, situação documental/jurídica e uso no cálculo continuam estados independentes. O acesso actual à cópia CBF supera a indisponibilidade assinalada em notas antigas; não activa regra nem apaga a nota histórica. Artigos, páginas, hashes e limites no recibo. A compilação não dispensa o período/alterações de cada tratamento, nem cria validação jurídica genérica adicional.
**Código por implementar em L7:** qualificação e persistência específicas; efeitos segregados; regras das famílias acima, por parcelas; conciliação sem duplicação; relatório/exportação correspondente. **Documentação por caso:** estatuto/reconhecimento ou enquadramento individual quando a fonte o exige; identificação de parcela/limite/cronologia; norma sectorial ainda sem correspondência; edição/campo de transporte afectado. Cada uma conserva exemplo e condição de retoma na linha correspondente. Não é necessário resolver todos os documentos para começar o primeiro incremento independente. L6 operacional não elimina este desenvolvimento; L7 delimitado não é L7 implementado; L8 conserva a liquidação final.
## 26/10/2026 — L7: qualificação, despesas autónomas e casos compatíveis em QA
**QA, sem instalação.** Base instalada preservada `5aaf1a56`; delimitação `d37fffb2`; ramo `codex/irpc-l7-common-autonomous-qa-20261026`, fotografia opcional `IRPC-normal-adjustments/10`. L6 continua operacional no âmbito demonstrado, com os cinco grupos de código e cinco documentais preservados. A implementação abaixo acrescenta apenas os tratamentos demonstrados; não conclui L7 nem o IRPC. Saldo final, retenções, pagamentos e aplicação anual de créditos permanecem em L8.
**Qualificação comum executável:** reutiliza sujeito/NUIT, âmbito, período, origem da oportunidade/dossier, sector e território; guarda condições, prova, fonte/artigo e período por tratamento. «Informação em falta», «ausência declarada», «não aplicável/condição negativa» e «calculado» têm resultados distintos. Desconhecido não vira zero. Período incompatível, identidade por reconciliar ou contradição afectam só o resultado dependente. A localização não escolhe taxa nem activa benefício. Os snapshots de origem ficam internos; o relatório apresenta contexto legível e as condições documentadas.
**Despesas61(4):** cada parcela aponta para uma linha `undocumented` do mapa36(1)g de L6, com acréscimo integral já calculado. Montante, documento e linha são reutilizados; L7 não introduz outro acréscimo nem outra despesa. A classificação legal e incidência são declaradas com prova própria; falta de anexo não classifica uma despesa. O imposto autónomo usa35% apenas nos casos qualificados. Duplicação da referência, parcela não correspondida, ausência contraditória ou informação insuficiente deixam o imposto reconciliado indeterminado; as parcelas conhecidas permanecem discriminadas. Condição negativa documentada conserva o ajustamentoL6 e não aplica imposto autónomo à parcela.
**Cooperativas12/14:** agrárias, artesanato ou culturais, residentes, com base ordinária integralmente elegível e ausência documentada de rendimentos sujeitos a retenção, aplicam redução de50% à taxa geral32%, ou16%. Não depende de seleccionar um sector semelhante. A qualificação especial pode coexistir com a opção «outro tratamento» da colectaL6: não exige fingir que a taxa reduzida é regime geral. Parcela mista, rendimentos retidos, outra entidade ou ausência contraditória conservam pendência própria; não recebem redução global presumida. O imposto autónomo de despesas não é reduzido por esta taxa.
**CBF16:** reutiliza identificadores e valores dos activosL6 suportados; imóvel novo do projecto ou máquinas industriais/agro-industriais das categorias correspondidas, com enquadramentoCBF3/9 e reconhecimento10 quando exigido (ou excepção identificada). Recorte inicial: primeiro exercício anual civil2026, método constante pela taxa normal máxima da tabela, activo desde01/01/2026, custo histórico novo, sem quotas anteriores/saída e sem cumulação de outros benefícios. Incrementa a taxa normal em50% e reutiliza limites de contabilização/saldo fiscal. Deduz apenas a diferença entre o mapa normal e o acelerado, sem alterar o activo de origem, os documentos ou os saldos oficiais. Quotas constantes gerais e demais cálculosL6 conservam o comportamento anterior quandoL7 está ausente.
| Caso sintético recuperado da API QA | Lucro/base e colecta de referênciaL6 | EfeitoL7 demonstrado | Resultado e limite |
| --- | --- | --- | --- |
| Despesa100 já acrescida36g | Lucro/base3230;colecta1033,60MZN | Novo ajustamento ao lucro0;imposto autónomo35 | Colecta combinada1068,60MZN;saldo finalL8indeterminado |
| Classificação da mesma despesa em falta | Lucro/base3230;colecta1033,60MZN preservados | Imposto autónomo indeterminado | Colecta combinada indeterminada;sem perda dos cálculos independentes |
| Condição negativa documentada na parcela | Ajustamento36g100 preservado | Parcela não aplicável;imposto autónomo0 justificado | Não confunde condição negativa com informação em falta |
| Ausência declarada de despesas autónomas | Lucro/base3130;colecta1001,60MZN | Ausência com suporte;imposto autónomo0 | Ausência contraditória com despesa36g fica pendente |
| Cooperativa integralmente abrangida | Base3130;colecta geral1001,60MZN | Taxa16%;colecta500,80MZN | Base/proveitos não alterados;sem retenções/créditos abatidos |
| Máquina industrial existente:base1000,taxa10%,quota contabilística120 | Quota normal100;lucro/base6260;colecta2003,20MZN | Quota acelerada150,mas dedução limitada120;diferença adicional20 | Lucro/base6240;colecta1996,80MZN;sem deduzir50 nem150 outra vez |
**Cálculo → gravação → recuperação → relatório:** fotografia10 opcional no mesmo livro/snapshot, chave com entradas/contexto e histórico imutável anterior. SemL7, a fotografia9 aceite e a sua chave/totais permanecem iguais. Recalcular não acumula imposto nem duplica o acréscimo. HTML e dossier financeiro mostram referênciaL6, efeitosL7, parcelas autónomas, fonte, condições, período e limitações; recuperação e download demonstrados no componente real. Uma mudança de origem/entradas torna a fotografia anterior histórica; não altera o registo anterior. M20/M22 conservam a preparaçãoL6 de referência: **este incremento não transporta efeitosL7 para campos oficiais por aproximação**, nem resolve as divergências documentais existentes.
**Provas novas:** Wayfinder `--with-form` gerou routes/actions pelo wrapper QA; TypeScript e build QA passaram. Dezanove testes dirigidos novos passaram, incluindo comparação exacta com a fotografia9 aceite, duplicação, período curto, opção especial de cooperativa, ausência contraditória, dados em falta e contexto apresentado sem despejar snapshots internos. API privada:1teste/108asserções, `simulator_fiscal_delta_20261021_test`,127.0.0.1:55441, transacção com rollback e guarda de identidade/base; seis casos recuperados com plano/livro/históricos idênticos. UI do componente real: alteração de classificação, informação em falta, ausência, cooperativa mista, cumulação pendente, gravação/recuperação local e exportação; sem erros de página. A prova local é distinta da API. Não houve testes/escrita no activo nem repetição das suites funcionais aceites de L3, ISPC, câmbio ou L5/L6.
**Entrega agrupada preparada:** qualificação + despesas autónomas, cooperativa integralmente elegível e amortizaçãoCBF16 no recorte acima. Despesa autónoma e cooperativa também foram demonstradas juntas:parcela35 sem redução,colecta sobre a base516,80 e combinada551,80MZN no exemplo de base3230. Isto não autoriza cumulação cooperativa+CBF16: essa combinação mantém resultado dependente indeterminado. A futura instalação segue o procedimento Git existente, com backup/restauro fresco e conferência do delta; não foi executada nesta passagem.
**SaldoL7 na mesma matriz:**
| Natureza | Ainda fora da cobertura / exemplo | Condição concreta de retoma |
| --- | --- | --- |
| Código | Despesa autónoma fora de linha36g calculada ou parcela ainda não segregada | Implementar origem/segregação correspondente e prova da incidência;não copiar montante para uma segunda despesa |
| Código | Cooperativa com actividade abrangida e outra não abrangida,ou rendimento sujeito a retenção | Segregar proveitos/custos/base e aplicar o tratamento apenas à parcela elegível;L5 conserva a retenção |
| Código | CBF16 em imóvel reabilitado,outra categoria,quota inferior à máxima,método degressivo,duodécimos,quotas anteriores ou exercício posterior | Corresponder regra e cronologia respectivas e reutilizar o activo/quotas existentes;pendênciaL6 limita apenas o activo dependente |
| Código/documento por caso | Cooperativa+CBF16 ou outro benefício positivo a cumular | Identificar compatibilidade,ordem e limites específicos;implementar a combinação,sem presumir soma de benefícios |
| Código | Mais-valias61-A,demais isenções/deduçõesCBF17–19,regimes sectoriais/territoriais e operações especiais | Implementar a família/parcelas já delimitadas na secção anterior;período e fonte específicos,sem nova pesquisa transversal |
| Documento por caso | Estatuto/título/excepçãoCBF ou prova das condições em falta;endereçoZEE sem estatuto | Juntar o elemento que a disposição exige ou registar condição negativa;localização isolada permanece insuficiente |
| Transporte/documento | CampoM20/M22 para efeitoL7,edição divergente ou representação não correspondida | Correspondência do campo/edição e regra de representação demonstradas;preservar o cálculo independente exacto |
| ÂmbitoL8 | Direito potencial ao créditoCBF15,aplicação anual de créditos,retenções,pagamentos e saldo final | Executar o mecanismo próprioL8;nenhuma dedução/compensação anual é presumida neste lote |
Fontes reutilizadas: inventário autorizado8143ficheiros; originaisCIRPC/alterações e CBF/compilaçãoAPIEX já identificados na delimitação,com hashes conservados. Sem activação por consulta ou revalidação jurídica genérica. Recibo: `docs/investmoz/simulations/irpc-l7-common-qa-20261026.json`. Provas locais: `outputs/irpc-l7-common/`; reprodução dirigida: `node --test tests/frontend/irpc-special.test.mjs`, `php tools/irpc-special-qa.php routes`, `php tools/irpc-special-qa.php test`, `tsc --noEmit`, build com `INVESTMOZ_QA_BUILD=1`.
## 26/10/2026 — preparação da entrega L7 e preservação do main concorrente
A entrega do âmbito QA `ab2ff2fd` integra o `main` concorrente `a2122dc3`, sem substituir as alterações de apresentação/navegação. Os seis ficheiros de execução L7 conservam exactamente o código QA;os oito ficheiros concorrentes conservam exactamente o código do main. Reutilizadas as provas19testes/API108/UI/tipos/build de L7. O conflito documental foi resolvido recuperando586linhas de histórico do manual que tinham sido removidas no merge concorrente,sem apagar a sua notaV2-01 no CSV. As3555linhas mantêm-se,com o único delta fiscal emAUD-SIM-INT02. O registo de instalação só será actualizado após backup/restauro fresco,conferência do destino e conclusão da entrega Git;esta nota não a antecipa.
## 26/10/2026 — primeira entrega agrupada L7 instalada pelo Git
Instalada `e07f89da3d59d06aa1b8c50c22a478b7b167bfdd` (integração do código QA `ab2ff2fdbcbe6fb94f03e4bc4cc7ccbd647d94fc` com o main concorrente`a2122dc3`),com `5aaf1a56f9d928331364fcc8b0d1528e51dba327` preservado como versão anterior. Os seis ficheiros de execução L7 são exactamente os da prova QA aceite;as sete alterações concorrentes de apresentação/navegação e o respectivo teste foram preservados. Recuperadas586linhas de histórico do manual removidas no merge concorrente;notaV2-01 conservada,sem alterar o seu conteúdo.
Backup fresco `2026-10-26T10:55:59Z`;restauro isolado sem rede/55441 verificou174tabelas por contagem/checksum e369ficheiros/configuração. Conferidos13ficheiros de execução do delta,50protegidos e31originais. Schema,roles/grants e permissões mantêm-se;172tabelas de negócio iguais ao backup. Cache/sessões reconciliadas por eventos operacionais e acessos públicos,sem inferir perda por RLS. A versão activa e a anterior foram preservadas durante o arquivo conferido de dependências antigas para recuperar espaço;nenhum dado,original ou backup foi eliminado.
Revisão/manifest público,marcadoresL7/L6/câmbio,assets e simuladorHTTP200 conferidos. Procedimento Git concluído;provas funcionais aceites19testes/API108/UI/tipos/build reutilizadas. Os controlos automáticos obrigatórios da instalação ficaram registados no recibo,sem nova ronda manual dos casos aceites. Sem migrações,importações,recálculo de históricos ou escrita privada sintética no activo.
Disponíveis apenas qualificação e tratamentos demonstrados:despesas61(4) sobre36g já ajustado,cooperativas12 integralmente abrangidas eCBF16 no recorte documentado. L6 permanece operacional no âmbito aceite;as suas pendências condicionam só dependentes. L7/IRPC não estão integralmente concluídos;localização não concede benefício;saldo final permaneceL8. O estado anterior deQA sem instalação é histórico. Recibo:`docs/investmoz/simulations/irpc-l7-common-delivery-20261026.json`.
## 26/10/2026 — saldo concreto de L7 após a primeira entrega agrupada
O âmbito demonstrado compreende qualificação comum, imposto autónomo61(4) sobre parcelas36g já calculadas emL6, cooperativas12 integralmente abrangidas e amortizaçãoCBF16 nos activos/período/método expressamente suportados. L7 permanece parcial. Este saldo distingue implementação de prova documental por caso; não cria outra matriz nem exige revalidação genérica das fontes aceites. L6 mantém o estado operacional delimitado e as suas pendências; só condiciona tratamentos que efectivamente dependam delas.
### Código ainda por implementar
| Tratamento / caso fora da cobertura | Exemplo | Condição concreta de retoma |
| --- | --- | --- |
| Despesas autónomas fora de parcela36g calculada e segregações adicionais | Despesa100 com apenas60 correspondidos no mapa de origem,ou encargo não incluído no resultado de partida | Implementar origem/parcela e reconciliação próprias,documentar incidência61(4) e impedir nova contabilização/acréscimo da mesma despesa. O ramo já entregue36g não é reaberto. |
| Cooperativas com rendimentos mistos/retidos;demais isenções por natureza da entidade,CIRPC9–14 | Cooperativa com actividade agrária e serviços não abrangidos;associação com rendimentos comerciais acessórios | Segregar proveitos,custos e base elegível e implementar o artigo específico. Não reduzir a base inteira nem estender a redução às retençõesL5. |
| ExtensõesCBF16 e combinações de benefícios | Imóvel reabilitado,método degressivo,quota inferior à máxima,duodécimos,quotas anteriores,ano posterior,cooperativa+CBF16 | Corresponder a regra temporal/método/contabilização e a compatibilidade/ordem/limite da combinação;reutilizar activo e quotas. Tabela ou casoL6 em falta impede apenas o activo dependente. |
| Mais-valias autónomas61-A e operações especiais | Ganho100 já incluído no resultado em2026;entrada de activos/fusão;perda transferida de outra sociedade | Implementar apuramento/parcela e reconciliação com resultadoL6,sem dupla incidência ou compensação de perdas presumida;para operações,aplicar54–56/41-A e preservar valores históricos. |
| Deduções/majoraçõesCBF17–19 e crédito potencialCBF15 | Formação sem ramo/base de limite;investimento novo com activos elegíveis e excluídos | Implementar elegibilidade,base,limite,ordem,janela temporal e não cumulação. CBF15 emL7 delimita direito/origem/crédito potencial;utilização anual,limitação por créditos/saldos e liquidação ficam emL8. |
| Regimes sectoriais/territoriais e disposições especiais | Projecto emZEE sem tratamentoIRPC correspondido;actividade mineira/petrolífera com regime próprio | Implementar a disposição/versão/período aplicáveis ao projecto e à parcela (CBF20–48 ou diploma específico). Endereço/código sectorial só identifica candidato;benefício aduaneiro não se transforma em benefícioIRPC. |
| Transporte de efeitosL7 paraM20/M22 | Imposto autónomo ou redução calculados mas sem campo/edição correspondente | Implementar apenas a correspondência demonstrada e a representação aplicável;conservar os montantes exactos e a preparaçãoL6 de referência,sem campo/taxa provisórios. |
### Dependências documentais que condicionam apenas o caso afectado
| Elemento em falta / dúvida concreta | Exemplo | Condição de retoma |
| --- | --- | --- |
| Classificação/incidência,parcela e período da operação | Há uma despesa36g e falta qualificar61(4);ou há actividade elegível e outra não abrangida | Associar prova/declaração da natureza e parcela ao exercício correcto. Informação em falta continua indeterminada;condição negativa e ausência declarada têm suporte próprio. Não inferir pela falta de anexo. |
| Estatuto e reconhecimento exigidos pela disposição | Endereço numaZEE sem estatuto do projecto;CBF16 sem instrumento10 ou norma de excepção | Juntar o elemento concreto exigido ou documentar a condição negativa/excepção aplicável. Não pedir aprovador ou parecer jurídico genérico adicional. |
| Norma/período/compatibilidade específicos ainda não correspondidos | Redução com termo31/12/2025 pretendida em2026;cumulação cooperativa+CBF16 | Disposição de vigência/prorrogação efectiva ou correspondência da combinação e seus limites. Sem informação nova,não repetir pesquisa transversal;prosseguir com os restantes casos. |
| Edição,campo ou representação do formulário | EfectoL7 com campoM20/M22 não identificado ou fracção sem regra de representação | Identificar exemplar/edição,instrução/campo e forma de representar o valor;limitar a pendência ao transporte afectado. O cálculo independente mantém-se disponível. |
**Limites conservados:** localização não concede benefícios automaticamente;benefício desconhecido não é zero;colecta normal,L7 e imposto autónomo permanecem discriminados. Retenções,pagamentos,aplicação anual de créditos e saldo final a pagar/recuperar continuam emL8. As provas aceites não são invalidadas por esta lista nem por uma dúvida documental num caso independente.
## 26/10/2026 — reconciliação do estado servido L7 e capacidade do instalador
Conferência autenticada por leitura em `2026-10-26T13:56:51.412248+02:00` (Africa/Johannesburg):o portal,o registo do instalador e o main actual coincidem em `e07f89da3d59d06aa1b8c50c22a478b7b167bfdd`. **L7 já está instalado no âmbito demonstrado**,com origemQA`ab2ff2fd`;o estado «ainda emQA,sem instalação» é histórico/desactualizado. A instalação terminou em26/10/2026 às13:02:35 locais;backup anterior às12:55:59 e restauro174tabelas/369ficheiros permanecem comprovados pelo recibo de entrega. Nesta passagem,o dump e o arquivo de ficheiros ainda coincidem com os hashes desse backup e a prova de restauro refere o mesmo dump. Não foi apresentado um novo backup/restauro como executado,nem repetida a instalação da revisão já activa.
**Partição do instalador e backup:**`/dev/md2 / ext4`;release,state,backup,tmp eDocker no mesmo dispositivo. Livres5.52GiB e21448231inodes de29089792. O código do instalador mantém o limiar5GiB;os ficheiros do backup observado ocupam0.164GiB. A leitura satisfaz5GiB+um backup desse tamanho,com margem0.35GiB. A release actual tem28674ficheiros e2503directórios sem seguir links,como referência de escala,não um novo limite arbitrário de inodes. Futuras entregas devem voltar a medir a capacidade imediatamente antes da operação;estes números não garantem uma carga futura diferente. Nenhuma limpeza local/remota foi executada;SGF TEMPO não foi afectado.
**Só o delta L7:**seis hashes de código correspondem à provaQA;revisão/manifest,sete marcadoresL7,quatroassets e entrada do simuladorHTTP200 conferidos. Reutilizadas as provas19testes/API108/UI/tipos/build e as provas anteriores de preservaçãoL6/L3/ISPC/câmbio;sem nova ronda funcional,escrita privada sintética,migração ou importação. A revisão activa e a anterior permanecem preservadas.
**Próximo conjunto delimitado para implementaçãoQA:CBF16 com duodécimos.** Reutilizar activos,tabela/taxa normal máxima,método constante,qualificaçãoCBF e periodizaçãoL6 existentes. Primeiro caso:exercício anual civil2026 com entrada em uso durante o ano;imóvel novo do projecto ou máquina industrial/agro-industrial já suportada;sem quotas anteriores,saída ou cumulação de outros benefícios. Ligar a quota mensalL6 ao incrementoCBF16,limitando ao contabilizado/saldo fiscal e mostrando apenas a diferença adicional. Demonstrar condição satisfeita,negativa,informação em falta e ausência declarada,cálculo→gravação→recuperação→relatório,efeitos no lucro/base/colecta e conservação dos históricos. Este conjunto está apenas delimitado:não é novo cálculo instalado.
Degressivo,reabilitados/usados/reavaliados,quotas anteriores e cumulação cooperativa+CBF16 continuam nos casos próprios. O saldo anterior de sete grupos de código e quatro dependências documentais permanece na mesma matriz,com exemplos/condições de retoma;nenhuma pendência foi apagada. Documento individual em falta limita só o activo/caso dependente. Localização não concede benefício. **L6 operacional delimitado;L7 parcial;retenções,pagamentos,créditos anuais e saldo final emL8.** Recibo:`docs/investmoz/simulations/irpc-l7-server-state-20261026.json`.
File diff suppressed because one or more lines are too long
+28 -11
View File
@@ -1,3 +1,4 @@
import { Link } from '@inertiajs/react';
import { ArrowRight, Search } from 'lucide-react';
import { useEffect, useState } from 'react';
import type { FormEvent } from 'react';
@@ -127,7 +128,6 @@ type PortalHeroProps = {
query: string;
setQuery: (value: string) => void;
onSearch: (event: FormEvent<HTMLFormElement>) => void;
onNavigate: (view: 'opportunities') => void;
stats?: HomeResponse['data']['stats'];
};
@@ -136,7 +136,6 @@ export default function PortalHero({
query,
setQuery,
onSearch,
onNavigate,
stats,
}: PortalHeroProps) {
const [currentSlide, setCurrentSlide] = useState(0);
@@ -261,20 +260,38 @@ export default function PortalHero({
</div>
</form>
<div className="mt-6 flex flex-wrap items-center justify-center gap-3">
<button
onClick={() => onNavigate('opportunities')}
className="inline-flex min-h-11 items-center gap-2 rounded-xl bg-white px-5 py-3 text-sm font-semibold text-[#101820] transition-colors hover:bg-slate-100 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white"
<div className="mt-4 flex flex-wrap items-center justify-center gap-2">
<Link
href="/porque-investir"
className="inline-flex min-h-11 items-center rounded-lg border border-white/50 bg-black/15 px-3 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white sm:min-h-9"
>
Consultar oportunidades{' '}
Porquê investir em Moçambique?
</Link>
<Link
href="/investimentos/iniciar"
className="inline-flex min-h-11 items-center rounded-lg border border-white/50 bg-black/15 px-3 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white sm:min-h-9"
>
Partir de uma ideia
</Link>
<Link
href="/oportunidades"
className="inline-flex min-h-11 items-center gap-1.5 rounded-lg bg-white px-3 py-1.5 text-sm font-semibold text-[#101820] transition-colors hover:bg-slate-100 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white sm:min-h-9"
>
Consultar oportunidades
<ArrowRight size={16} aria-hidden="true" />
</button>
<a
</Link>
<Link
href="/simulador-fiscal"
className="inline-flex min-h-11 items-center rounded-xl border border-white/50 bg-black/15 px-5 py-3 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white"
className="inline-flex min-h-11 items-center rounded-lg border border-white/50 bg-black/15 px-3 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white sm:min-h-9"
>
Simulador Fiscal
</a>
</Link>
<Link
href="/sectores"
className="inline-flex min-h-11 items-center rounded-lg border border-white/50 bg-black/15 px-3 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-white sm:min-h-9"
>
Sectores de investimento
</Link>
</div>
<dl
@@ -1,3 +1,4 @@
import {SimulationIrpcSpecial} from '@/components/simulation-irpc-special';
import {SimulationIrpcFormPreparation} from '@/components/simulation-irpc-form-preparation';
import {SimulationIrpcPeriodFx} from '@/components/simulation-irpc-period-fx';
import {SimulationIrpcDepreciation} from '@/components/simulation-irpc-depreciation';
@@ -39,8 +40,9 @@ export function SimulationIrpcNormal({draft,onChange}:{draft:Record<string,unkno
<SimulationIrpcCosts draft={draft} book={b} save={save}/>
<SimulationIrpcTaxableBase draft={draft} book={b} save={save}/>
<SimulationIrpcAssessment book={b} save={save}/>
<SimulationIrpcSpecial draft={draft} book={b} save={save}/>
<SimulationIrpcFormPreparation draft={draft} book={b} save={save}/>
<button type="button" onClick={()=>{try{save(recordNormal(draft,b));}catch(e){setError(String(e));}}}>Calcular e guardar ajustamentos L6</button>
<button type="button" onClick={()=>{try{save(recordNormal(draft,b));}catch(e){setError(String(e));}}}>Calcular e guardar L6 e tratamentos L7 preparados</button>
<button type="button" onClick={()=>{try{const html=normalHtml(draft),url=URL.createObjectURL(new Blob([html],{type:'text/html;charset=utf-8'})),a=document.createElement('a');a.href=url;a.download='IRPC-normal-ajustamentos.html';a.click();URL.revokeObjectURL(url);setError('');}catch(e){setError(String(e));}}}>Exportar mapa parcial L6</button>
{normalReportRows(draft).map((r,n)=><p key={n}>{r[1]} — {r[2]} — {r[3]}</p>)}
</section>;
@@ -0,0 +1,24 @@
import type {NormalBook} from '@/lib/irpc-normal';
import {newSpecialInput,newSpecialExpense,newAcceleratedAsset,specialSources,type SpecialInput,type Qualification} from '@/lib/irpc-special';
type Props={draft:Record<string,unknown>;book:NormalBook;save:(b:NormalBook)=>void};
const states=[['','Informação em falta'],['known','Tratamento conhecido — qualificar condições'],['absent','Ausência declarada com suporte'],['not_applicable','Tratamento não aplicável — justificar']]as const;
function QualificationFields({label,value,onChange}:{label:string;value:Qualification;onChange:(v:Qualification)=>void}){
const field=(key:'from'|'to'|'reference'|'periodReference',text:string)=><label className="block">{text}<input aria-label={label+' — '+text} value={value[key]} onChange={e=>onChange({...value,[key]:e.target.value})}/></label>;
return<div className="space-y-2"><label className="block">Estado — {label}<select aria-label={'Estado — '+label} value={value.state} onChange={e=>onChange({...value,state:e.target.value as Qualification['state'],eligible:''})}>{states.map(([v,t])=><option key={v} value={v}>{t}</option>)}</select></label>{value.state==='known'&&<label className="block">Condições — {label}<select aria-label={'Condições — '+label} value={value.eligible} onChange={e=>onChange({...value,eligible:e.target.value as Qualification['eligible']})}><option value="">Por esclarecer</option><option value="yes">Sim — condições documentadas</option><option value="no">Não — condição negativa documentada</option></select></label>}{field('reference','Prova das condições, ausência ou não aplicação')}{field('from','Período — início (AAAA-MM-DD)')}{field('to','Período — termo (AAAA-MM-DD)')}{field('periodReference','Suporte do período e da vigência aplicável')}</div>;
}
export function SimulationIrpcSpecial({draft,book:b,save}:Props){
const i=b.special;
const start=()=>{const next=newSpecialInput(),p=b.periodsFx??b.schedules?.period;for(const part of[next.expenses,next.cooperative,next.acceleration])Object.assign(part.qualification,{from:p?.from??b.year+'-01-01',to:p?.to??b.year+'-12-31'});save({...b,special:next});};
if(!i)return<section className="rounded border p-3"><h5>L7 — benefícios e casos especiais</h5><p>Preparação opcional e separada do percursoL6 já entregue. Localização e sector não activam benefícios. A liquidação final permanece emL8.</p><button type="button" onClick={start}>Preparar qualificação L7</button></section>;
const change=(patch:Partial<SpecialInput>)=>save({...b,special:{...i,...patch}});
const yesno=(label:string,value:string,onChange:(v:''|'yes'|'no')=>void)=><label className="block">{label}<select aria-label={label} value={value} onChange={e=>onChange(e.target.value as ''|'yes'|'no')}><option value="">Informação em falta</option><option value="yes">Sim — documentado</option><option value="no">Não — documentado</option></select></label>;
return<section aria-label="L7 — qualificação e tratamentos" className="space-y-3 rounded border p-3"><h5>L7 — qualificação comum e tratamentos documentados</h5><p>Reutiliza sujeito, NUIT, período, despesas e activos L6. Contexto herdado:sector {String(draft.sector_id??'por identificar')};província {String(draft.province_id??'por identificar')}. A localização, por si só, não concede benefícios. Os valores L6 continuam como referência;os efeitosL7 são apresentados separadamente. Saldo final a pagar/recuperar:âmbitoL8.</p>
<fieldset className="space-y-2 rounded border p-3"><legend>Despesas — tributação autónoma61(4)</legend><p>{specialSources.expenses}</p><QualificationFields label="Despesas autónomas" value={i.expenses.qualification} onChange={qualification=>change({expenses:{...i.expenses,qualification}})}/>
<button type="button" onClick={()=>change({expenses:{...i.expenses,rows:[...i.expenses.rows,...(b.schedules?.rows??[]).filter(r=>r.rule==='undocumented'&&!i.expenses.rows.some(x=>x.scheduleId===r.id)).map(r=>({...newSpecialExpense('expense-'+r.id),scheduleId:r.id}))]}})}>Reutilizar despesas36g de L6 para qualificar</button>
{i.expenses.rows.map((r,index)=>{const origin=b.schedules?.rows.find(x=>x.id===r.scheduleId),patch=(p:Partial<typeof r>)=>change({expenses:{...i.expenses,rows:i.expenses.rows.map(x=>x.id===r.id?{...x,...p}:x)}});return<fieldset key={r.id} className="rounded border p-2"><legend>{origin?origin.document+'/'+origin.line:'Parcela por corresponder'} — {origin?.amount??'Indeterminado'} MZN</legend><p>O acréscimo36g já pertence aL6;esta linha só apura o eventual imposto autónomo.</p><label className="block">Natureza legal da despesa<select aria-label={'Natureza da despesa '+(index+1)} value={r.nature} onChange={e=>patch({nature:e.target.value as typeof r.nature})}><option value="">Informação em falta</option><option value="undocumented">Encargo não devidamente documentado</option><option value="confidential">Despesa confidencial</option><option value="illicit">Despesa ilícita</option><option value="other">Outra natureza — correspondência própria</option></select></label>{yesno('Incidência61(4) — parcela '+(index+1),r.eligible,eligible=>patch({eligible}))}<label className="block">Suporte da classificação e incidência<input aria-label={'Suporte da despesa '+(index+1)} value={r.reference} onChange={e=>patch({reference:e.target.value})}/></label><button type="button" onClick={()=>change({expenses:{...i.expenses,rows:i.expenses.rows.filter(x=>x.id!==r.id)}})}>Retirar qualificação da parcela {index+1}</button></fieldset>;})}</fieldset>
<fieldset className="space-y-2 rounded border p-3"><legend>Cooperativas abrangidas — artigo12</legend><p>{specialSources.cooperative} Este incremento exige base integralmente elegível;parcelas mistas continuam explícitas.</p><QualificationFields label="Cooperativa" value={i.cooperative.qualification} onChange={qualification=>change({cooperative:{...i.cooperative,qualification}})}/>{(i.cooperative.qualification.state==='known'||i.cooperative.kind!==''||i.cooperative.allIncomeEligible!==''||i.cooperative.withheldIncome!=='')&&<><label className="block">Tipo de cooperativa documentado<select value={i.cooperative.kind} onChange={e=>change({cooperative:{...i.cooperative,kind:e.target.value as typeof i.cooperative.kind}})}><option value="">Por identificar</option><option value="agrarian">Agrária</option><option value="craft">Artesanato</option><option value="cultural">Cultural</option><option value="other">Outra — não correspondida</option></select></label>{yesno('Base ordinária integralmente elegível',i.cooperative.allIncomeEligible,allIncomeEligible=>change({cooperative:{...i.cooperative,allIncomeEligible}}))}<label className="block">Rendimentos sujeitos a retenção<select value={i.cooperative.withheldIncome} onChange={e=>change({cooperative:{...i.cooperative,withheldIncome:e.target.value as typeof i.cooperative.withheldIncome}})}><option value="">Informação em falta</option><option value="absent">Ausência documentada</option><option value="known">Existem — segregação própria em falta</option></select></label></>}</fieldset>
<fieldset className="space-y-2 rounded border p-3"><legend>Amortizações aceleradas — CBF16</legend><p>{specialSources.acceleration} Apenas activos já suportados,primeiro ano civil2026 e método constante;outras combinações permanecem por corresponder.</p><QualificationFields label="Amortização acelerada" value={i.acceleration.qualification} onChange={qualification=>change({acceleration:{...i.acceleration,qualification}})}/>{i.acceleration.qualification.state==='known'&&<>{yesno('EnquadramentoCBF3 e pressupostos9 documentados',i.acceleration.cbfRequirements,cbfRequirements=>change({acceleration:{...i.acceleration,cbfRequirements}}))}<label className="block">ReconhecimentoCBF10<select value={i.acceleration.recognition} onChange={e=>change({acceleration:{...i.acceleration,recognition:e.target.value as typeof i.acceleration.recognition}})}><option value="">Informação em falta</option><option value="documented">Instrumento/reconhecimento documentado</option><option value="not_required">Excepção prevista — identificar norma e suporte</option></select></label><label className="block">Instrumento ou norma da excepção<input value={i.acceleration.recognitionReference} onChange={e=>change({acceleration:{...i.acceleration,recognitionReference:e.target.value}})}/></label>{yesno('Ausência documentada de outros benefícios a cumular',i.acceleration.noOtherBenefits,noOtherBenefits=>change({acceleration:{...i.acceleration,noOtherBenefits}}))}</>}
<button type="button" onClick={()=>change({acceleration:{...i.acceleration,rows:[...i.acceleration.rows,newAcceleratedAsset(crypto.randomUUID())]}})}>Qualificar activo existente paraCBF16</button>{i.acceleration.rows.map((r,index)=>{const patch=(p:Partial<typeof r>)=>change({acceleration:{...i.acceleration,rows:i.acceleration.rows.map(x=>x.id===r.id?{...x,...p}:x)}});return<fieldset key={r.id} className="rounded border p-2"><legend>Activo qualificado {index+1}</legend><label className="block">Activo do mapaL6<select value={r.assetId} onChange={e=>patch({assetId:e.target.value})}><option value="">Seleccione activo existente</option>{b.depreciation?.assets.map(a=><option key={a.id} value={a.id}>{a.description} — {a.assetKey}</option>)}</select></label><label className="block">Afectação documentada<select value={r.kind} onChange={e=>patch({kind:e.target.value as typeof r.kind})}><option value="">Por identificar</option><option value="new_project_building">Imóvel novo utilizado no projecto</option><option value="rehabilitated_project_building">Imóvel reabilitado — regra ainda por corresponder</option><option value="industrial_equipment">Máquina/equipamento industrial</option><option value="agroindustrial_equipment">Máquina/equipamento agro-industrial</option><option value="other">Outro — correspondência própria</option></select></label>{yesno('Condições do activoCBF16 — '+(index+1),r.eligible,eligible=>patch({eligible}))}<label className="block">Prova da afectação e condições do activo<input value={r.reference} onChange={e=>patch({reference:e.target.value})}/></label><button type="button" onClick={()=>change({acceleration:{...i.acceleration,rows:i.acceleration.rows.filter(x=>x.id!==r.id)}})}>Retirar tratamento do activo {index+1}</button></fieldset>;})}</fieldset>
<p>Use «Calcular e guardar» abaixo para gravar uma nova versão e apresentar os efeitos. Os históricos anteriores são conservados. M20/M22 mantém apenas correspondências demonstradas;camposL7 não são preenchidos por aproximação.</p></section>;
}
+22 -4
View File
@@ -58,10 +58,28 @@ const menuTranslations = [
'solicitudes recibidas',
],
[
'Porquê investir em Moçambique',
'Why invest in Mozambique',
'Pourquoi investir au Mozambique',
'Por qué invertir en Mozambique',
'Porquê investir em Moçambique?',
'Why invest in Mozambique?',
'Pourquoi investir au Mozambique ?',
'Por qué invertir en Mozambique?',
],
[
'Partir de uma ideia',
'Start with an idea',
'Partir d’une idée',
'Partir de una idea',
],
[
'Consultar oportunidades',
'Browse opportunities',
'Consulter les opportunités',
'Consultar oportunidades',
],
[
'Simulador Fiscal',
'Tax simulator',
'Simulateur fiscal',
'Simulador fiscal',
],
[
'Oportunidades de investimento',
+1 -1
View File
@@ -30,7 +30,7 @@ const names: Record<string, string> = {
'/contacto': 'Contacto',
'/politica-de-privacidade': 'Política de Privacidade',
'/termos-de-uso': 'Termos de Uso',
'/porque-investir': 'Porquê investir em Moçambique',
'/porque-investir': 'Porquê investir em Moçambique?',
'/investimentos/iniciar': 'Iniciar ou continuar investimento',
'/explorar/agronegocio': 'Explorar agronegócio',
'/agronegocio': 'Artigo de agronegócio',
+2 -2
View File
@@ -30,7 +30,7 @@ const ratio=(a:FiscalFraction,b:FiscalFraction)=>fraction(BigInt(a.numerator)*Bi
const date=(v:string)=>/^20\d{2}-\d{2}-\d{2}$/.test(v)&&Number.isFinite(Date.parse(v))&&new Date(v).toISOString().slice(0,10)===v;
const month=(v:string)=>Number(v.slice(0,4))*12+Number(v.slice(5,7))-1;
const show=(v:FiscalFraction|null)=>{if(!v)return'Indeterminado';const p=fractionPresentation(v);return(p.approximate?'≈':'')+p.decimal+' MZN'+(p.approximate?' (exacto '+v.numerator+'/'+v.denominator+')':'');};
export function calculateNormalDepreciation(input:NormalDepreciationInput,source:{currency:string;accountingLines:Array<{code:string;total:string}>}|null,period:{from:string;to:string},claims:Array<{sourceCode:string;document:string;line:string;amount:string}>,short=false){
export function calculateNormalDepreciation(input:NormalDepreciationInput,source:{currency:string;accountingLines:Array<{code:string;total:string}>}|null,period:{from:string;to:string},claims:Array<{sourceCode:string;document:string;line:string;amount:string}>,short=false,acceleratedIds:ReadonlySet<string>=new Set()){
validateNormalDepreciation(input);const pending:string[]=[];
if(!input.completenessReference.trim())pending.push('Reconciliação integral dos activos e quotas anteriores com a depreciação da origem em falta.');
if(source?.currency!=='MZN'||!date(period.from)||!date(period.to)||!period.to.startsWith('2026-')||(!short&&month(period.to)-month(period.from)!==11||short&&(month(period.to)<month(period.from)||month(period.to)-month(period.from)>=11)))pending.push('Período anual emMZN com termo em2026 por reconciliar; períodos curtos permanecem separados.');
@@ -60,7 +60,7 @@ export function calculateNormalDepreciation(input:NormalDepreciationInput,source
if(a.method==='low_value'){if(cmp(cost,fraction(20000n))>0n||!yesno(a.individual,'Activo individual fora de conjunto depreciado como um todo')||cmp(priorFiscal,zero())!==0n||a.start<period.from||a.start>period.to)throw Error('Art17:valor unitário até20000MZN,activo individual e início no período,sem amortização fiscal anterior; condições em falta/incompatíveis.');quota=remaining;months=month(period.to)-month(a.start)+1;notes.push('Art17:opção de depreciação integral em um período,limitada ao que está contabilizado e ao saldo fiscal.');}
else{
if(!entry||!maxRate||!maxLifeMonths)throw Error('Taxa aplicável não identificada.');
if(a.method==='constant'){if(!/^\d+(?:\.\d{1,6})?$/.test(a.rate))throw Error('Taxa constante escolhida por identificar.');const selected=decimalFraction(a.rate);if(cmp(selected,multiply(maxRate,fraction(1n,2n)))<0n||cmp(selected,maxRate)>0n)throw Error('Taxa constante fora do recorte entre metade da máxima e a máxima;quotas inferiores exigem correspondência própria dos limites de vida útil, artigos5/7.');quota=multiply(taxBasis,multiply(selected,fraction(1n,100n)));notes.push('Quota constante pela taxa escolhida:'+a.rate+'%;tabela'+entry.table+'/'+entry.code+'.');}
if(a.method==='constant'){if(!/^\d+(?:\.\d{1,6})?$/.test(a.rate))throw Error('Taxa constante escolhida por identificar.');const selected=decimalFraction(a.rate);if(cmp(selected,multiply(maxRate,fraction(1n,2n)))<0n||cmp(selected,maxRate)>0n)throw Error('Taxa constante fora do recorte entre metade da máxima e a máxima;quotas inferiores exigem correspondência própria dos limites de vida útil, artigos5/7.');quota=multiply(taxBasis,multiply(selected,fraction(acceleratedIds.has(a.id)?3n:1n,acceleratedIds.has(a.id)?200n:100n)));if(acceleratedIds.has(a.id))notes.push('CBF16:L7 qualificado,incremento50% da taxa normal;mantidos contabilização e saldo fiscal.');notes.push('Quota constante pela taxa escolhida:'+a.rate+'%;tabela'+entry.table+'/'+entry.code+'.');}
else if(a.method==='declining'){if(!yesno(a.newTangible,'Activo tangível novo adquirido a terceiros/construído')||['building','furniture','software'].includes(entry.kind)||entry.kind==='vehicle'&&a.vehicleException!=='yes')throw Error('Art6:quotas degressivas só nos activos tangíveis novos elegíveis;edifícios,mobiliário/equipamento social,intangíveis e veículos sem excepção ficam separados.');const life=ratio(fraction(100n),maxRate),maxFactor=cmp(life,fraction(5n))<0n?fraction(3n,2n):cmp(life,fraction(6n))<=0n?fraction(2n):fraction(5n,2n);if(!/^\d+(?:\.\d{1,6})?$/.test(a.factor))throw Error('Coeficiente degressivo escolhido em falta.');const factor=decimalFraction(a.factor);if(cmp(factor,zero())<=0n||cmp(factor,maxFactor)>0n)throw Error('Coeficiente degressivo excede o máximo do artigo8:1,5/2/2,5 conforme vida útil mínima.');quota=multiply(remaining,multiply(maxRate,multiply(factor,fraction(1n,100n))));notes.push('Art8:saldo fiscal por amortizar ×taxa máxima'+entry.rate+'% ×coeficiente'+a.factor+';máximo'+fractionPresentation(maxFactor).decimal+'.');
if(yesno(a.switchToStraight,'Opção pela regra de saldo/vida útil restante8(2)')){if(!yesno(a.priorFullQuotas,'Condição das quotas anteriores8(2)')||!a.start.endsWith('-01-01')||period.from!=='2026-01-01'||a.timing!=='annual')throw Error('Art8(2):condição das quotas anteriores por documentar;este recorte da opção exige início emJaneiro e período anual civil.');const remainingYears=subtractFractions(life,fraction(BigInt(2026-Number(a.start.slice(0,4)))));if(cmp(remainingYears,zero())<=0n)throw Error('Art8(2):vida útil mínima esgotada;sem dividir por anos inexistentes.');const linear=ratio(remaining,remainingYears);if(cmp(quota,linear)<0n){quota=linear;notes.push('Art8(2):usado saldo/número de anos de vida útil mínima restantes,com condições anteriores documentadas.');}}
}else throw Error('Método de amortização por identificar.');
+10 -7
View File
@@ -1,3 +1,4 @@
import {irpcSpecialVersion,validateSpecial,calculateSpecial,specialReportRows,specialDependency,type SpecialInput,type SpecialModel} from './irpc-special.ts';
import {normalFormPreparationVersion,validateNormalFormPreparation,prepareNormalForms,normalFormPreparationReport,type NormalFormPreparationInput,type NormalFormPreparationModel} from './irpc-normal-form-preparation.ts';
import {normalPeriodFxVersion,validateNormalPeriodFx,mapNormalPeriodFx,normalPeriodFxDependency,normalPeriodFxReport,type NormalPeriodFxInput,type NormalPeriodFxModel} from './irpc-normal-period-fx.ts';
import {normalDepreciationVersion,validateNormalDepreciation,calculateNormalDepreciation,normalDepreciationReport,type NormalDepreciationInput,type NormalDepreciationModel} from './irpc-normal-depreciation.ts';
@@ -15,8 +16,8 @@ import {addFractions,decimalFraction,fraction,fractionPresentation,type FiscalFr
export const irpcNormalVersion='IRPC-normal-adjustments/1';
export const irpcNormalSource='CIRPC Lei34/2007 art17(1),PDF6/p768(60):resultado e correcções;art36(1)c,PDF10/p768(64):multas e encargos por infracções sem origem contratual,incluindo juros compensatórios. Lei4/2012 PDF2 altera17(6)/acrescenta36(1)o;Lei19/2013 PDF2 mantém36(1)a–o e acrescenta p/q. Lei12/2025 altera3/5/20/62/67/75,adita61-A e revoga39/47/75(2)/76;sem alteração deste recorte36(1)c. Não é apuramento integral nem Modelo20/22.';
export type NormalAdjustment={id:string;sourceCode:string;document:string;line:string;amount:string;rule:''|'noncontractual_fine'|'compensatory_interest'|'other';included:''|'yes'|'no';reference:string};
export type NormalBook={version:1;year:string;mappingReference:string;scope:''|'resident_general'|'ep_general'|'other';scopeReference:string;rows:NormalAdjustment[];profit?:NormalProfitInput;base?:NormalBaseInput;assessment?:NormalAssessmentInput;schedules?:NormalSchedules;costs?:NormalCostsInput;depreciation?:NormalDepreciationInput;forms?:NormalFormPreparationInput;periodsFx?:NormalPeriodFxInput;result?:NormalRecord;history?:NormalRecord[]};
type NormalModel={formPreparation?:NormalFormPreparationModel;periodsFx?:NormalPeriodFxModel;depreciation?:NormalDepreciationModel;costs?:NormalCostsModel;fiscalPeriod?:{kind:string;from:string;to:string;reference:string;pending:string[]};schedules?:SchedulesModel;currentLoss?:FiscalFraction|null;assessment?:NormalAssessmentModel;colecta?:FiscalFraction|null;base?:NormalBaseModel;profit?:NormalProfitModel;version:string;year:string;currency:string;origin:'projected';accountingProfit:FiscalFraction|null;additions:FiscalFraction;partialAdjustedResult:FiscalFraction|null;taxableProfit:FiscalFraction|null;taxableBase:FiscalFraction|null;tax:null;rows:Array<NormalAdjustment&{status:'calculated'|'indeterminate'|'outside_scope';adjustment:FiscalFraction|null;reason:string}>;pending:string[];source:string};
export type NormalBook={version:1;year:string;mappingReference:string;scope:''|'resident_general'|'ep_general'|'other';scopeReference:string;rows:NormalAdjustment[];special?:SpecialInput;profit?:NormalProfitInput;base?:NormalBaseInput;assessment?:NormalAssessmentInput;schedules?:NormalSchedules;costs?:NormalCostsInput;depreciation?:NormalDepreciationInput;forms?:NormalFormPreparationInput;periodsFx?:NormalPeriodFxInput;result?:NormalRecord;history?:NormalRecord[]};
export type NormalModel={special?:SpecialModel;formPreparation?:NormalFormPreparationModel;periodsFx?:NormalPeriodFxModel;depreciation?:NormalDepreciationModel;costs?:NormalCostsModel;fiscalPeriod?:{kind:string;from:string;to:string;reference:string;pending:string[]};schedules?:SchedulesModel;currentLoss?:FiscalFraction|null;assessment?:NormalAssessmentModel;colecta?:FiscalFraction|null;base?:NormalBaseModel;profit?:NormalProfitModel;version:string;year:string;currency:string;origin:'projected';accountingProfit:FiscalFraction|null;additions:FiscalFraction;partialAdjustedResult:FiscalFraction|null;taxableProfit:FiscalFraction|null;taxableBase:FiscalFraction|null;tax:null;rows:Array<NormalAdjustment&{status:'calculated'|'indeterminate'|'outside_scope';adjustment:FiscalFraction|null;reason:string}>;pending:string[];source:string};
type NormalRecord={key:string;createdAt:string;model:NormalModel};
export const newNormalBook=():NormalBook=>({version:1,year:'',mappingReference:'',scope:'',scopeReference:'',rows:[]});
export const newNormalAdjustment=(id:string):NormalAdjustment=>({id,sourceCode:'',document:'',line:'',amount:'',rule:'',included:'',reference:''});
@@ -28,6 +29,7 @@ export function rawNormalFinancialSource(d:Record<string,unknown>){
export function normalFinancialSource(d:Record<string,unknown>){const raw=rawNormalFinancialSource(d),input=normalBook(d).periodsFx;return input?mapNormalPeriodFx(d,input,raw).source:raw;}
function store(d:Record<string,unknown>){const s=JSON.parse(String(d.modelo_a_snapshot||'{"version":1,"books":{}}'));if(s.version!==1||!s.books||typeof s.books!=='object'||Array.isArray(s.books))throw Error('Livros fiscais não recuperáveis;originais preservados.');return s;}
export function validateNormal(b:NormalBook){
if(b?.special!==undefined)validateSpecial(b.special);
if(b?.forms!==undefined)validateNormalFormPreparation(b.forms);
if(b?.periodsFx!==undefined)validateNormalPeriodFx(b.periodsFx);
if(b?.depreciation!==undefined)validateNormalDepreciation(b.depreciation);
@@ -39,13 +41,13 @@ export function validateNormal(b:NormalBook){
if(!b||b.version!==1||['year','mappingReference','scopeReference'].some(k=>typeof b[k as 'year']!=='string')||!['','resident_general','ep_general','other'].includes(b.scope)||!Array.isArray(b.rows)||b.history!==undefined&&!Array.isArray(b.history))throw Error('Preparação IRPC normal não recuperável.');
for(const r of b.rows)if(!r||Object.keys(newNormalAdjustment('')).some(k=>typeof r[k as keyof NormalAdjustment]!=='string')||!['','noncontractual_fine','compensatory_interest','other'].includes(r.rule)||!['','yes','no'].includes(r.included))throw Error('Ajustamento IRPC não recuperável;original conservado.');
if(new Set(b.rows.map(r=>r.id)).size!==b.rows.length)throw Error('Identificador de ajustamento duplicado.');
for(const r of [b.result,...(b.history??[])])if(r&&(!r.model||![irpcNormalVersion,normalProfitVersion,normalBaseVersion,normalAssessmentVersion,normalSchedulesVersion,normalCostsVersion,normalDepreciationVersion,normalPeriodFxVersion,normalFormPreparationVersion].includes(r.model.version)||typeof r.key!=='string'||typeof r.createdAt!=='string'||!Array.isArray(r.model.rows)||!Array.isArray(r.model.pending)))throw Error('Histórico IRPC normal não recuperável.');
for(const r of [b.result,...(b.history??[])])if(r&&(!r.model||![irpcSpecialVersion,irpcNormalVersion,normalProfitVersion,normalBaseVersion,normalAssessmentVersion,normalSchedulesVersion,normalCostsVersion,normalDepreciationVersion,normalPeriodFxVersion,normalFormPreparationVersion].includes(r.model.version)||typeof r.key!=='string'||typeof r.createdAt!=='string'||!Array.isArray(r.model.rows)||!Array.isArray(r.model.pending)))throw Error('Histórico IRPC normal não recuperável.');
}
export function normalBook(d:Record<string,unknown>):NormalBook{
const m=store(d).irpcNormal;if(m===undefined)return newNormalBook();if(!m||typeof m!=='object'||Array.isArray(m))throw Error('Mapa IRPC normal não recuperável.');const b=m[acquisitionScope(d)]??newNormalBook();validateNormal(b);return b;
}
export function saveNormalBook(d:Record<string,unknown>,b:NormalBook){validateNormal(b);const s=store(d);if(s.irpcNormal!==undefined&&(!s.irpcNormal||typeof s.irpcNormal!=='object'||Array.isArray(s.irpcNormal)))throw Error('Mapa IRPC normal não recuperável.');return JSON.stringify({...s,irpcNormal:{...s.irpcNormal,[acquisitionScope(d)]:b}});}
function key(d:Record<string,unknown>,b:NormalBook){return JSON.stringify([b.forms?normalFormPreparationVersion:b.periodsFx?normalPeriodFxVersion:b.depreciation?normalDepreciationVersion:b.costs?normalCostsVersion:b.schedules?normalSchedulesVersion:b.assessment?normalAssessmentVersion:b.base?normalBaseVersion:b.profit?normalProfitVersion:irpcNormalVersion,acquisitionScope(d),d.business_plan_snapshot??'',b.year,b.mappingReference,b.scope,b.scopeReference,b.rows,...(b.profit?[b.profit]:[]),...(b.base?[b.base]:[]),...(b.assessment?[b.assessment]:[]),...(b.schedules?[b.schedules]:[]),...(b.costs?[b.costs]:[]),...(b.depreciation?[b.depreciation]:[]),...(b.periodsFx?[b.periodsFx,normalPeriodFxDependency(d,b.periodsFx)]:[]),...(b.forms?[b.forms]:[])]);}
function key(d:Record<string,unknown>,b:NormalBook){return JSON.stringify([b.special?irpcSpecialVersion:b.forms?normalFormPreparationVersion:b.periodsFx?normalPeriodFxVersion:b.depreciation?normalDepreciationVersion:b.costs?normalCostsVersion:b.schedules?normalSchedulesVersion:b.assessment?normalAssessmentVersion:b.base?normalBaseVersion:b.profit?normalProfitVersion:irpcNormalVersion,acquisitionScope(d),d.business_plan_snapshot??'',b.year,b.mappingReference,b.scope,b.scopeReference,b.rows,...(b.profit?[b.profit]:[]),...(b.base?[b.base]:[]),...(b.assessment?[b.assessment]:[]),...(b.schedules?[b.schedules]:[]),...(b.costs?[b.costs]:[]),...(b.depreciation?[b.depreciation]:[]),...(b.periodsFx?[b.periodsFx,normalPeriodFxDependency(d,b.periodsFx)]:[]),...(b.forms?[b.forms]:[]),...(b.special?[b.special,specialDependency(d)]:[])]);}
export function normalCurrent(d:Record<string,unknown>,b:NormalBook){return !!b.result&&b.result.key===key(d,b);}
const zero=()=>fraction(0n,1n);
const cents=(s:string)=>{if(!/^-?\d+(?:\.\d{1,2})?$/.test(s))throw Error('Montante MZN inválido;máximo dois decimais.');const v=decimalFraction(s.startsWith('-')?s.slice(1):s);return s.startsWith('-')?fraction(-BigInt(v.numerator),BigInt(v.denominator)):v;};
@@ -94,7 +96,8 @@ export function calculateNormal(d:Record<string,unknown>,b:NormalBook):NormalMod
const assessment=b.assessment?calculateNormalAssessment(b.assessment,base?.taxableBase??null,{year:b.year,scope:b.scope,extended:!!b.schedules||!!periodsFx,short:!!periodsFx?.short,currency:source?.currency??'',...(fiscalPeriod?{period:{from:fiscalPeriod.from,to:fiscalPeriod.to}}:{})}):undefined;
if(assessment)pending.push(...assessment.pending,assessment.finalBalance.reason);
const currentLoss=b.schedules&&profit?.taxableProfit&&BigInt(profit.taxableProfit.numerator)<0n?fraction(-BigInt(profit.taxableProfit.numerator),BigInt(profit.taxableProfit.denominator)):null;
const model:NormalModel={...(periodsFx?{periodsFx}:{}),...(depreciation?{depreciation}:{}),...(costs?{costs}:{}),...(schedules?{schedules,currentLoss,fiscalPeriod}:{}),...(assessment?{assessment,colecta:assessment.colecta}:{}),...(base?{base}:{}),...(profit?{profit}:{}),version:b.forms?normalFormPreparationVersion:b.periodsFx?normalPeriodFxVersion:b.depreciation?normalDepreciationVersion:b.costs?normalCostsVersion:b.schedules?normalSchedulesVersion:b.assessment?normalAssessmentVersion:b.base?normalBaseVersion:b.profit?normalProfitVersion:irpcNormalVersion,year:b.year,currency:source?.currency??'',origin:'projected',accountingProfit,additions,partialAdjustedResult:contextReady&&rows.length>0&&rows.every(r=>r.status==='calculated')&&accountingProfit?addFractions([accountingProfit,additions]):null,taxableProfit:profit?.taxableProfit??null,taxableBase:base?.taxableBase??null,tax:null,rows,pending,source:irpcNormalSource+(periodsFx?' '+periodsFx.rule:b.schedules?' Mapas complementares: CIRPC18/21/22/24/36; Decreto72/2013 art3–7. EP: CIRPC15(1)c, apenas resultado imputável ao estabelecimento no regime geral, anual2026/MZN.':'')};
const model:NormalModel={...(periodsFx?{periodsFx}:{}),...(depreciation?{depreciation}:{}),...(costs?{costs}:{}),...(schedules?{schedules,currentLoss,fiscalPeriod}:{}),...(assessment?{assessment,colecta:assessment.colecta}:{}),...(base?{base}:{}),...(profit?{profit}:{}),version:b.special?irpcSpecialVersion:b.forms?normalFormPreparationVersion:b.periodsFx?normalPeriodFxVersion:b.depreciation?normalDepreciationVersion:b.costs?normalCostsVersion:b.schedules?normalSchedulesVersion:b.assessment?normalAssessmentVersion:b.base?normalBaseVersion:b.profit?normalProfitVersion:irpcNormalVersion,year:b.year,currency:source?.currency??'',origin:'projected',accountingProfit,additions,partialAdjustedResult:contextReady&&rows.length>0&&rows.every(r=>r.status==='calculated')&&accountingProfit?addFractions([accountingProfit,additions]):null,taxableProfit:profit?.taxableProfit??null,taxableBase:base?.taxableBase??null,tax:null,rows,pending,source:irpcNormalSource+(periodsFx?' '+periodsFx.rule:b.schedules?' Mapas complementares: CIRPC18/21/22/24/36; Decreto72/2013 art3–7. EP: CIRPC15(1)c, apenas resultado imputável ao estabelecimento no regime geral, anual2026/MZN.':'')};
if(b.special)model.special=calculateSpecial(d,b,model,source);
if(b.forms){model.formPreparation=prepareNormalForms(b.forms,model,source);model.pending.push(...model.formPreparation.pending.map(p=>'Preparação M20/M22: '+p));}
return model;
}
@@ -102,5 +105,5 @@ export function recordNormal(d:Record<string,unknown>,b:NormalBook,now=new Date(
const money=(v:FiscalFraction|null)=>v?fractionPresentation(v).decimal+' MZN':'Indeterminado';
function normalBaseReport(m:NormalBaseModel):Array<[string,string,string,string]>{return[['IRPC normal — L6','Matéria colectável — deduções/perdas',`Lucro tributável:${money(m.taxableProfit)};perdas propostas elegíveis:${money(m.requestedLosses)};perdas deduzidas nesta simulação:${money(m.deductedLosses)};benefícios deduzidos:${money(m.benefitDeduction)};matéria colectável simulada:${money(m.taxableBase)};imposto a pagar:Indeterminado. ${m.pending.join(' | ')}`,`NUIT:${m.input.subjectNuit};${m.input.identityReference};método:${m.input.method==='direct'?'Declarativo/directo':m.input.method==='indirect'?'Indirecto':'Por identificar'};${m.input.methodReference};perdas:${m.input.lossesState==='absent'?'Ausência declarada':m.input.lossesState==='known'?'Conhecidas':'Informação em falta'};${m.input.lossesReference};objecto:${m.input.unchangedObject==='yes'?'Sem alteração declarada':m.input.unchangedObject==='no'?'Alteração declarada':'Por esclarecer'};${m.input.objectReference};${m.source}`],['IRPC normal — L6','Benefícios à matéria colectável',`Estado:${m.input.benefits.state==='known'?'Valor conhecido':m.input.benefits.state==='absent'?'Ausência declarada':'Informação em falta'};montante original:${m.input.benefits.amount||'Não preenchido'};dedução:${money(m.benefitDeduction)};não inclui créditos à colecta ou retenções sofridas.`,m.input.benefits.reference],...m.losses.map(l=>['IRPC normal — L6','Perda fiscal de '+l.year,`Estado:${l.status==='eligible'?'Elegível neste recorte':l.status==='excluded'?'Excluída neste exercício':'Indeterminada'};apurada:${l.assessed};utilizada antes:${l.previouslyUsed};saldo:${money(l.available)};utilização proposta:${l.requested};dedução nesta simulação:${money(l.deducted)};saldo aritmético posterior:${money(l.remaining)};último exercício ordinário:${l.lastOrdinaryYear??'Por determinar'};${l.reason}`,`NUIT:${l.subjectNuit};${l.reference};sem consumo do saldo oficial nem reporte automático.`]as[string,string,string,string])];}
function normalAssessmentReport(m:NormalAssessmentModel):Array<[string,string,string,string]>{return[['IRPC normal — L6','Colecta — regime normal',`Matéria colectável:${money(m.taxableBase)};taxa:${m.rate?m.rate.numerator+'%':'Por identificar'};colecta simulada:${money(m.colecta)};${m.classification};${m.centExact===false?'Valor racional exacto com fracção de cêntimo;sem arredondamento fiscal aplicado.':''}${m.pending.join(' | ')}`,`Exercício:${m.period.year};período:${m.period.from}–${m.period.to};${m.input.reference};${m.rule};${m.source}`],['IRPC normal — L6','Saldo final — âmbito L8','A pagar:Indeterminado;a recuperar:Indeterminado. '+m.finalBalance.reason,'Sequência:lucro tributável → matéria colectável → colecta → saldo final;retenções,pagamentos e créditos anuais reservados aL8.']];}
export function normalReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=normalBook(d),r=b.result;if(!r)return[];const m=r.model;return[['IRPC normal — L6','Ajustamentos ao resultado financeiro',`Exercício:${m.year};resultado contabilístico antes de imposto:${money(m.accountingProfit)};acréscimos demonstrados:${money(m.additions)};resultado parcial ajustado:${money(m.partialAdjustedResult)};${m.profit?'lucro tributável simulado:'+money(m.taxableProfit)+(m.base?';matéria colectável simulada:'+money(m.taxableBase)+(m.assessment?';colecta simulada:'+money(m.colecta??null)+';saldo final a pagar ou recuperar:Indeterminado (L8).':';imposto a pagar:Indeterminado.'):';matéria colectável/imposto:Indeterminados.'):'lucro tributável/matéria colectável/imposto:Indeterminados.'} Projecção com pressupostos;${m.pending.join(' | ')}`,`${normalCurrent(d,b)?'Entradas correspondentes':'Histórico;origem ou entradas alteradas'};${r.createdAt};${m.source}`],...(m.formPreparation?normalFormPreparationReport(m.formPreparation):[]),...(m.periodsFx?normalPeriodFxReport(m.periodsFx):[]),...(m.depreciation?normalDepreciationReport(m.depreciation):[]),...(m.costs?normalCostReport(m.costs):[]),...(m.base?normalBaseReport(m.base):[]),...(m.assessment?normalAssessmentReport(m.assessment):[]),...(m.schedules?[['IRPC normal — L6','Mapas complementares',`Efeito líquido adicional:${money(m.schedules.net)};perda fiscal do próprio exercício:${money(m.currentLoss??null)};sem reporte ou consumo automático. ${m.schedules.pending.join(' | ')}`,m.schedules.source]as[string,string,string,string],...m.schedules.effects.map(e=>{const i=m.schedules!.input.rows.find(r=>r.id===e.id)!;return['IRPC normal — L6',i.document+'/'+i.line,`Montante:${money(e.amount)};efeito:${money(e.effect)};${e.reason}`,`${i.reference};exercício de imputação:${i.fiscalYear||'Não aplicável'}`]as[string,string,string,string];}),...m.schedules.assets.map(a=>['IRPC normal — L6',a.description,`Depreciação contabilística:${money(a.accountingValue)};quota fiscal:${money(a.fiscal)};acréscimo:${money(a.adjustment)};${a.reason}`,`${a.tableReference};${a.reference}`]as[string,string,string,string]),['IRPC normal — L6','Juros financeiros ordinários',`Remanescente aceite no recorte:${money(m.schedules.interest)};não corresponde a juros de mora/compensatórios L5.`,m.schedules.input.interest.reference]as[string,string,string,string]]:[]),...(m.schedules&&!m.formPreparation?[...normalFormFields(m).fields.map(f=>['IRPC normal — L6','M22 campo '+f.code+' — '+f.label,`${f.display};exacto:${f.value?f.value.numerator+'/'+f.value.denominator:'Indeterminado'};transcrição:${f.transcriptionReady?'Preparação parcial com valor exacto ao cêntimo':'Pendente ou sem aplicação'};${f.reason}`,normalFormFields(m).source]as[string,string,string,string]),...normalFormFields(m).m20.fields.map(f=>['IRPC normal — L6','M20 A.1 — conta '+f.account+' — '+f.label,`${f.display};representação em meticais inteiros:${f.transcriptionReady?'Exacta':'Pendente'};${f.reason}`,`${f.reference};${normalFormFields(m).m20.source}`]as[string,string,string,string]),['IRPC normal — L6','M20 — correspondência',normalFormFields(m).m20.reason,normalFormFields(m).m20.source]as[string,string,string,string]]:[]),...m.rows.map(r=>['IRPC normal — L6',r.document+'/'+r.line,`${({calculated:'Calculado neste recorte',indeterminate:'Indeterminado',outside_scope:'Fora deste recorte'})[r.status]};montante:${r.amount};acréscimo:${money(r.adjustment)};${r.reason}`,`Origem:${({revenue:'Receitas',cost_of_sales:'Custo das vendas',operating_expenses:'Despesas operacionais',personnel:'Pessoal',depreciation:'Depreciação contabilística',interest_expense:'Juros reconhecidos'}as Record<string,string>)[r.sourceCode]??'Por corresponder'};incluído:${r.included==='yes'?'Sim':r.included==='no'?'Não':'Por demonstrar'};suporte:${r.reference}`]as[string,string,string,string]),...(m.profit?[...m.profit.lines.map(l=>['IRPC normal — L6','Conferência: '+l.label,`Estado:${l.state==='known'?'Valor conhecido':l.state==='absent'?'Ausência declarada':'Informação em falta'};origem:${l.amount};acréscimos:${money(l.addedBack)};remanescente:${money(l.remainder)};${l.reason}`,l.reference]as[string,string,string,string]),...m.profit.topics.map(t=>['IRPC normal — L6',t.label,`Estado:${t.state==='known'?'Valor conhecido':t.state==='absent'?'Ausência declarada':'Informação em falta'};montante:${money(t.value)};${t.reason}`,t.reference]as[string,string,string,string]),['IRPC normal — L6','Âmbito da conferência',m.profit.input.completenessReference,m.profit.source]as[string,string,string,string]]:[])];}catch(e){return[['IRPC normal — L6','Não recuperável',String(e),'Originais conservados.']];}}
export function normalHtml(d:Record<string,unknown>){const b=normalBook(d);if(!normalCurrent(d,b))throw Error('Calcule e guarde as entradas actuais antes de exportar.');const esc=(s:string)=>s.replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]!));return'<!doctype html><html lang="pt"><meta charset="utf-8"><title>IRPC normal — ajustamentos</title><h1>L6 — mapa parcial de ajustamentos</h1><p>Projecção pelos pressupostos do plano. Não é demonstração contabilística,liquidação ou Modelo20/22.</p>'+normalReportRows(d).map(r=>'<section><h2>'+esc(r[1])+'</h2><p>'+esc(r[2])+'</p><small>'+esc(r[3])+'</small></section>').join('')+'</html>';}
export function normalReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=normalBook(d),r=b.result;if(!r)return[];const m=r.model;return[['IRPC normal — L6','Ajustamentos ao resultado financeiro',`Exercício:${m.year};resultado contabilístico antes de imposto:${money(m.accountingProfit)};acréscimos demonstrados:${money(m.additions)};resultado parcial ajustado:${money(m.partialAdjustedResult)};${m.profit?'lucro tributável simulado:'+money(m.taxableProfit)+(m.base?';matéria colectável simulada:'+money(m.taxableBase)+(m.assessment?';colecta simulada:'+money(m.colecta??null)+';saldo final a pagar ou recuperar:Indeterminado (L8).':';imposto a pagar:Indeterminado.'):';matéria colectável/imposto:Indeterminados.'):'lucro tributável/matéria colectável/imposto:Indeterminados.'} Projecção com pressupostos;${m.pending.join(' | ')}`,`${normalCurrent(d,b)?'Entradas correspondentes':'Histórico;origem ou entradas alteradas'};${r.createdAt};${m.source}`],...(m.special?specialReportRows(m.special):[]),...(m.formPreparation?normalFormPreparationReport(m.formPreparation):[]),...(m.periodsFx?normalPeriodFxReport(m.periodsFx):[]),...(m.depreciation?normalDepreciationReport(m.depreciation):[]),...(m.costs?normalCostReport(m.costs):[]),...(m.base?normalBaseReport(m.base):[]),...(m.assessment?normalAssessmentReport(m.assessment):[]),...(m.schedules?[['IRPC normal — L6','Mapas complementares',`Efeito líquido adicional:${money(m.schedules.net)};perda fiscal do próprio exercício:${money(m.currentLoss??null)};sem reporte ou consumo automático. ${m.schedules.pending.join(' | ')}`,m.schedules.source]as[string,string,string,string],...m.schedules.effects.map(e=>{const i=m.schedules!.input.rows.find(r=>r.id===e.id)!;return['IRPC normal — L6',i.document+'/'+i.line,`Montante:${money(e.amount)};efeito:${money(e.effect)};${e.reason}`,`${i.reference};exercício de imputação:${i.fiscalYear||'Não aplicável'}`]as[string,string,string,string];}),...m.schedules.assets.map(a=>['IRPC normal — L6',a.description,`Depreciação contabilística:${money(a.accountingValue)};quota fiscal:${money(a.fiscal)};acréscimo:${money(a.adjustment)};${a.reason}`,`${a.tableReference};${a.reference}`]as[string,string,string,string]),['IRPC normal — L6','Juros financeiros ordinários',`Remanescente aceite no recorte:${money(m.schedules.interest)};não corresponde a juros de mora/compensatórios L5.`,m.schedules.input.interest.reference]as[string,string,string,string]]:[]),...(m.schedules&&!m.formPreparation?[...normalFormFields(m).fields.map(f=>['IRPC normal — L6','M22 campo '+f.code+' — '+f.label,`${f.display};exacto:${f.value?f.value.numerator+'/'+f.value.denominator:'Indeterminado'};transcrição:${f.transcriptionReady?'Preparação parcial com valor exacto ao cêntimo':'Pendente ou sem aplicação'};${f.reason}`,normalFormFields(m).source]as[string,string,string,string]),...normalFormFields(m).m20.fields.map(f=>['IRPC normal — L6','M20 A.1 — conta '+f.account+' — '+f.label,`${f.display};representação em meticais inteiros:${f.transcriptionReady?'Exacta':'Pendente'};${f.reason}`,`${f.reference};${normalFormFields(m).m20.source}`]as[string,string,string,string]),['IRPC normal — L6','M20 — correspondência',normalFormFields(m).m20.reason,normalFormFields(m).m20.source]as[string,string,string,string]]:[]),...m.rows.map(r=>['IRPC normal — L6',r.document+'/'+r.line,`${({calculated:'Calculado neste recorte',indeterminate:'Indeterminado',outside_scope:'Fora deste recorte'})[r.status]};montante:${r.amount};acréscimo:${money(r.adjustment)};${r.reason}`,`Origem:${({revenue:'Receitas',cost_of_sales:'Custo das vendas',operating_expenses:'Despesas operacionais',personnel:'Pessoal',depreciation:'Depreciação contabilística',interest_expense:'Juros reconhecidos'}as Record<string,string>)[r.sourceCode]??'Por corresponder'};incluído:${r.included==='yes'?'Sim':r.included==='no'?'Não':'Por demonstrar'};suporte:${r.reference}`]as[string,string,string,string]),...(m.profit?[...m.profit.lines.map(l=>['IRPC normal — L6','Conferência: '+l.label,`Estado:${l.state==='known'?'Valor conhecido':l.state==='absent'?'Ausência declarada':'Informação em falta'};origem:${l.amount};acréscimos:${money(l.addedBack)};remanescente:${money(l.remainder)};${l.reason}`,l.reference]as[string,string,string,string]),...m.profit.topics.map(t=>['IRPC normal — L6',t.label,`Estado:${t.state==='known'?'Valor conhecido':t.state==='absent'?'Ausência declarada':'Informação em falta'};montante:${money(t.value)};${t.reason}`,t.reference]as[string,string,string,string]),['IRPC normal — L6','Âmbito da conferência',m.profit.input.completenessReference,m.profit.source]as[string,string,string,string]]:[])];}catch(e){return[['IRPC normal — L6','Não recuperável',String(e),'Originais conservados.']];}}
export function normalHtml(d:Record<string,unknown>){const b=normalBook(d);if(!normalCurrent(d,b))throw Error('Calcule e guarde as entradas actuais antes de exportar.');const esc=(s:string)=>s.replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]!));return'<!doctype html><html lang="pt"><meta charset="utf-8"><title>IRPC normal — ajustamentos</title><h1>IRPC — L6 de referência e tratamentos L7 quando qualificados</h1><p>Projecção pelos pressupostos do plano. Não é demonstração contabilística,liquidação ou Modelo20/22.</p>'+normalReportRows(d).map(r=>'<section><h2>'+esc(r[1])+'</h2><p>'+esc(r[2])+'</p><small>'+esc(r[3])+'</small></section>').join('')+'</html>';}
+125
View File
@@ -0,0 +1,125 @@
import type {NormalBook,NormalModel} from './irpc-normal.ts';
import {calculateNormalBase} from './irpc-normal-base.ts';
import {calculateNormalAssessment} from './irpc-normal-assessment.ts';
import {calculateNormalDepreciation,type NormalDepreciationModel} from './irpc-normal-depreciation.ts';
import {addFractions,subtractFractions,decimalFraction,fraction,fractionPresentation,type FiscalFraction} from './fiscal-rational.ts';
export const irpcSpecialVersion='IRPC-normal-adjustments/10';
export const specialSources={expenses:'CIRPC,Lei34/2007,art61(4),PDF17/p768(71):35% sobre encargos não devidamente documentados e despesas confidenciais/ilícitas,sem prejuízo do36(1)g. Exercício2026;sem regra inferida da falta de anexo.',cooperative:'CIRPC,Lei34/2007,art12/14,PDF5/p768(59),e61(1):cooperativas agrárias,de artesanato e culturais;redução de50% da taxa geral32%=16%;rendimentos sujeitos a retenção excluídos deste benefício. Recorte2026,residente,parcela ordinária integralmente elegível.',acceleration:'CBF,Lei4/2009,art3/4/9/10/16;compilação oficial APIEX pp66–68/72:incremento50% das taxas normais nos imóveis novos do projecto e,nas mesmas condições,imóveis reabilitados/máquinas e equipamentos industriais ou agro-industriais. Decreto72/2013 art3(3):limite contabilizado e saldo fiscal. Recorte constante pela taxa normal máxima da tabela,primeiro exercício anual2026,sem cumulação presumida.'}as const;
export type Qualification={state:''|'known'|'absent'|'not_applicable';eligible:''|'yes'|'no';from:string;to:string;reference:string;periodReference:string};
export const newQualification=():Qualification=>({state:'',eligible:'',from:'',to:'',reference:'',periodReference:''});
export type SpecialExpense={id:string;scheduleId:string;nature:''|'undocumented'|'confidential'|'illicit'|'other';eligible:''|'yes'|'no';reference:string};
export type AcceleratedAsset={id:string;assetId:string;kind:''|'new_project_building'|'rehabilitated_project_building'|'industrial_equipment'|'agroindustrial_equipment'|'other';eligible:''|'yes'|'no';reference:string};
export type SpecialInput={version:1;expenses:{qualification:Qualification;rows:SpecialExpense[]};cooperative:{qualification:Qualification;kind:''|'agrarian'|'craft'|'cultural'|'other';allIncomeEligible:''|'yes'|'no';withheldIncome:''|'absent'|'known'};acceleration:{qualification:Qualification;cbfRequirements:''|'yes'|'no';recognition:''|'documented'|'not_required';recognitionReference:string;noOtherBenefits:''|'yes'|'no';rows:AcceleratedAsset[]}};
export const newSpecialInput=():SpecialInput=>({version:1,expenses:{qualification:newQualification(),rows:[]},cooperative:{qualification:newQualification(),kind:'',allIncomeEligible:'',withheldIncome:''},acceleration:{qualification:newQualification(),cbfRequirements:'',recognition:'',recognitionReference:'',noOtherBenefits:'',rows:[]}});
export const newSpecialExpense=(id:string):SpecialExpense=>({id,scheduleId:'',nature:'',eligible:'',reference:''});
export const newAcceleratedAsset=(id:string):AcceleratedAsset=>({id,assetId:'',kind:'',eligible:'',reference:''});
const choices=(v:unknown,allowed:string[])=>typeof v==='string'&&allowed.includes(v);
export function validateSpecial(i:SpecialInput){
if(!i||i.version!==1||!i.expenses||!i.cooperative||!i.acceleration)throw Error('Qualificação L7 não recuperável;originais conservados.');
for(const q of[i.expenses.qualification,i.cooperative.qualification,i.acceleration.qualification])if(!q||!choices(q.state,['','known','absent','not_applicable'])||!choices(q.eligible,['','yes','no'])||['from','to','reference','periodReference'].some(k=>typeof q[k as 'from']!=='string'))throw Error('Condição/período L7 não recuperável.');
for(const [rows,keys]of [[i.expenses.rows,Object.keys(newSpecialExpense(''))],[i.acceleration.rows,Object.keys(newAcceleratedAsset(''))]]as const){if(!Array.isArray(rows)||new Set(rows.map(r=>r.id)).size!==rows.length||rows.some(r=>!r||keys.some(k=>typeof(r as unknown as Record<string,unknown>)[k]!=='string')||!choices(r.eligible,['','yes','no'])))throw Error('Parcela L7 não recuperável ou identificador repetido.');}
if(i.expenses.rows.some(r=>!choices(r.nature,['','undocumented','confidential','illicit','other']))||i.acceleration.rows.some(r=>!choices(r.kind,['','new_project_building','rehabilitated_project_building','industrial_equipment','agroindustrial_equipment','other'])))throw Error('Natureza L7 desconhecida.');
if(!choices(i.cooperative.kind,['','agrarian','craft','cultural','other'])||!choices(i.cooperative.allIncomeEligible,['','yes','no'])||!choices(i.cooperative.withheldIncome,['','absent','known'])||!choices(i.acceleration.cbfRequirements,['','yes','no'])||!choices(i.acceleration.noOtherBenefits,['','yes','no'])||!choices(i.acceleration.recognition,['','documented','not_required'])||typeof i.acceleration.recognitionReference!=='string')throw Error('Parâmetro L7 não recuperável.');
}
type Status='calculated'|'absent'|'not_applicable'|'indeterminate';
type Decision={status:Status;reason:string;pending:string[]};
const z=()=>fraction(0n),mul=(v:FiscalFraction,n:bigint,d=1n)=>fraction(BigInt(v.numerator)*n,BigInt(v.denominator)*d);
const cmp=(a:FiscalFraction,b:FiscalFraction)=>BigInt(a.numerator)*BigInt(b.denominator)-BigInt(b.numerator)*BigInt(a.denominator);
const iso=(s:string)=>/^20\d{2}-\d{2}-\d{2}$/.test(s)&&Number.isFinite(Date.parse(s))&&new Date(s).toISOString().slice(0,10)===s;
export function specialContext(d:Record<string,unknown>){return Object.fromEntries(['context_opportunity','context_opportunity_snapshot','context_applicability_snapshot','context_reuse','sector_id','sector_id_label','province_id','province_id_label','district_id','district_id_label','admin_post_id','admin_post_id_label','locality_id','locality_id_label','selection_labels'].map(k=>[k,d[k]??null]));}
export const specialDependency=(d:Record<string,unknown>)=>JSON.stringify(specialContext(d));
const specialPeriod=(b:NormalBook,m:NormalModel)=>b.periodsFx?{from:b.periodsFx.from,to:b.periodsFx.to,pending:m.periodsFx?.pending??[]}:m.fiscalPeriod??{from:b.year+'-01-01',to:b.year+'-12-31',pending:[]};
function qualify(q:Qualification,b:NormalBook,m:NormalModel):Decision{
const pending:string[]=[],p=specialPeriod(b,m);
if(!q.state)pending.push('Informação em falta:identifique o estado do tratamento.');
if(!q.reference.trim())pending.push('Falta prova/declaração das condições ou da ausência/não aplicação.');
if(!iso(q.from)||!iso(q.to)||q.from!==p.from||q.to!==p.to||!q.periodReference.trim())pending.push('Período do tratamento deve corresponder ao período fiscal documentado,com suporte próprio;sem transpor vigência.');
if(b.year!=='2026'||m.currency!=='MZN'||!b.base?.subjectNuit.match(/^\d{9}$/)||!b.base.identityReference.trim()||!b.scopeReference.trim()||!['resident_general','ep_general'].includes(b.scope)||p.pending.length)pending.push('Sujeito/NUIT,âmbito ou período2026 emMZN por reconciliar na base existente.');
if(q.state==='known'&&!q.eligible)pending.push('Condições documentadas por qualificar:sim,não ou informação em falta.');
if(q.state!=='known'&&q.eligible)pending.push('Estado de ausência/não aplicação/informação em falta não admite condição de benefício preenchida.');
if(pending.length)return{status:'indeterminate',pending,reason:pending.join(' ')};
const status=q.state==='absent'?'absent':q.state==='not_applicable'||q.eligible==='no'?'not_applicable':'calculated';
return{status,pending,reason:status==='absent'?'Ausência declarada com suporte;efeito zero neste período.':status==='not_applicable'?'Tratamento não aplicável/condição negativa documentada;percurso normal conservado.':'Condições e período documentados no recorte.'};
}
function fail(d:Decision,reason:string){d.status='indeterminate';d.pending.push(reason);d.reason=d.pending.join(' ');}
export function calculateSpecial(draft:Record<string,unknown>,b:NormalBook,m:NormalModel,source:Parameters<typeof calculateNormalDepreciation>[1]){
const i=b.special!;validateSpecial(i);const expenseDecision=qualify(i.expenses.qualification,b,m),coopDecision=qualify(i.cooperative.qualification,b,m),accDecision=qualify(i.acceleration.qualification,b,m);
const existing=(b.schedules?.rows??[]).filter(r=>r.rule==='undocumented');
if(expenseDecision.status==='absent'&&(existing.length||i.expenses.rows.length))fail(expenseDecision,'Ausência declarada contradiz despesas36g ou linhasL7 presentes;reconcilie sem apagar o ajustamento.');
if(expenseDecision.status!=='calculated'&&i.expenses.rows.length&&expenseDecision.status!=='indeterminate')fail(expenseDecision,'Estado global e parcelas da despesa contraditórios;qualifique as parcelas ou conserve apenas a declaração.');
const expenses=i.expenses.rows.map(r=>{
const origin=existing.find(x=>x.id===r.scheduleId),effect=m.schedules?.effects.find(x=>x.id===r.scheduleId);let amount:FiscalFraction|null=effect?.amount??null,tax:FiscalFraction|null=null,status:Status='indeterminate';const reasons:string[]=[];
if(expenseDecision.status!=='calculated')reasons.push(expenseDecision.reason);
if(!origin||!effect?.effect||!effect.amount||cmp(effect.effect,effect.amount)!==0n)reasons.push('Seleccione ajustamento36g calculado emL6;imposto autónomo não acrescenta novamente a despesa.');
if(i.expenses.rows.filter(x=>x.scheduleId===r.scheduleId).length!==1)reasons.push('Despesa L6 repetida no imposto autónomo;uma referência por parcela.');
if(!r.reference.trim()||!r.eligible||!r.nature)reasons.push('Falta classificação legal documentada da despesa;ausência de anexo não prova61(4).');
if(!reasons.length){status=r.eligible==='no'?'not_applicable':r.nature==='other'?'indeterminate':'calculated';if(status==='indeterminate')reasons.push('Outra natureza por corresponder;sem taxa provisória.');else tax=status==='calculated'?mul(amount!,35n,100n):z();}
return{...structuredClone(r),document:origin?.document??'',line:origin?.line??'',sourceCode:origin?.sourceCode??'',amount,l6Adjustment:effect?.effect??null,additionalProfitAdjustment:z(),rate:status==='calculated'?fraction(35n):null,tax,status,reason:reasons.join(' ')||(status==='calculated'?'CIRPC61(4):despesa ×35%;ajustamento36g reutilizado,sem duplicação.':'Condição negativa documentada;sem imposto autónomo aplicado à parcela.')};
});
if(expenseDecision.status==='calculated'){
if(!existing.length&&!expenses.length)fail(expenseDecision,'Não há parcelas conhecidas;declare ausência com suporte ou seleccione despesas36g.');
if(existing.some(r=>!expenses.some(x=>x.scheduleId===r.id)))fail(expenseDecision,'Há despesa36g sem qualificação autónoma;corresponda cada parcela ou justifique a sua não aplicação.');
for(const r of expenses)if(r.status==='indeterminate')fail(expenseDecision,(r.document||r.id)+': '+r.reason);
}
const knownAutonomous=addFractions(expenses.flatMap(r=>r.tax?[r.tax]:[])),autonomousTax=expenseDecision.status==='indeterminate'?null:expenseDecision.status==='calculated'?knownAutonomous:z();
if(coopDecision.status==='absent'&&['agrarian','craft','cultural'].includes(i.cooperative.kind)&&i.cooperative.allIncomeEligible==='yes'&&i.cooperative.withheldIncome==='absent')fail(coopDecision,'Ausência de redução contradiz os dados positivos de cooperativa integralmente elegível;reconcilie a declaração sem apagar os dados.');
if(coopDecision.status==='calculated'){
if(b.scope!=='resident_general'||!['agrarian','craft','cultural'].includes(i.cooperative.kind))fail(coopDecision,'Art12:tipo de cooperativa abrangida e residência por documentar;outras entidades têm correspondência própria.');
if(i.cooperative.allIncomeEligible!=='yes'||i.cooperative.withheldIncome!=='absent')fail(coopDecision,'Recorte exige base ordinária integralmente elegível e ausência documentada de rendimentos sujeitos a retenção;parcelas mistas/retidas exigem segregação própria,sem redução global presumida.');
}
if(accDecision.status==='absent'&&i.acceleration.rows.length)fail(accDecision,'Ausência de amortização acelerada contradiz activos seleccionados.');
if(accDecision.status!=='calculated'&&i.acceleration.rows.length&&accDecision.status!=='indeterminate')fail(accDecision,'Não aplicação global com activos seleccionados:reconcilie o estado e as parcelas.');
if(accDecision.status==='calculated'){
if(i.acceleration.cbfRequirements!=='yes'||!i.acceleration.recognition||!i.acceleration.recognitionReference.trim())fail(accDecision,'Falta enquadramentoCBF3/9 e reconhecimento10 quando exigido;excepção deve ter norma/suporte,não localização.');
if(i.acceleration.noOtherBenefits!=='yes')fail(accDecision,'CumulaçãoCBF4 por corresponder;este recorte não combina outros benefícios positivos.');
if(coopDecision.status==='calculated')fail(accDecision,'Combinação de redução cooperativa comCBF16 ainda não correspondida;cada caso independente continua demonstrável.');
if(!b.depreciation||!m.depreciation||!i.acceleration.rows.length)fail(accDecision,'Seleccione activos do mapaL6 já reconciliado;sem criar activo ou quota paralelos.');
}
const accelerations=i.acceleration.rows.map(r=>{
const a=b.depreciation?.assets.find(x=>x.id===r.assetId),base=m.depreciation?.assets.find(x=>x.id===r.assetId),issues:string[]=[];let status:Status='indeterminate';
if(accDecision.status!=='calculated')issues.push(accDecision.reason);
if(!r.reference.trim()||!r.eligible||!r.kind)issues.push('Condição/afectação do activo ao projecto por documentar.');
if(i.acceleration.rows.filter(x=>x.assetId===r.assetId).length!==1)issues.push('Activo repetido no benefício.');
if(!a||base?.status!=='calculated')issues.push('ActivoL6 inexistente ou cálculo de origem indeterminado.');
if(!issues.length&&r.eligible==='no')status='not_applicable';
else if(!issues.length&&a){
const building=r.kind==='new_project_building'&&base?.catalog?.kind==='building',equipment=['industrial_equipment','agroindustrial_equipment'].includes(r.kind)&&['machine','laundry_machine'].includes(a.category);
if(!building&&!equipment)issues.push('Categoria/afectação fora do recorte:imóvel novo ou máquina industrial/agro-industrial correspondida;reabilitados e outras categorias/métodos exigem regra própria.');
if(base?.catalog&&cmp(decimalFraction(a.rate),decimalFraction(base.catalog.rate))!==0n)issues.push('RecorteCBF16 usa a taxa normal máxima da tabela;opção por quota inferior exige correspondência própria,sem a acelerar por aproximação.');
if(a.method!=='constant'||a.timing!=='annual'||a.start!=='2026-01-01'||a.exitState!=='absent'||a.previousAccounting!=='0'||a.previousFiscal!=='0'||a.priorAvailable!=='0'||m.fiscalPeriod?.from!=='2026-01-01'||m.fiscalPeriod?.to!=='2026-12-31')issues.push('CBF16 inicial:primeiro exercício anual civil2026,método constante,sem quotas anteriores ou saída;duodécimos e recuperação anterior continuam separados.');
if(!issues.length)status='calculated';
}
return{...structuredClone(r),assetKey:a?.assetKey??'',description:a?.description??'',status,reason:issues.join(' ')||(status==='calculated'?'Activo existente elegível;taxa normal ×1,5,com limite contabilístico e saldo fiscal.':'Condição negativa documentada;quota normal mantida.')};
});
let acceleratedDepreciation:NormalDepreciationModel|null=null,additionalDeduction:FiscalFraction|null=accDecision.status==='indeterminate'?null:z();
if(accDecision.status==='calculated'){
for(const r of accelerations)if(r.status==='indeterminate')fail(accDecision,(r.description||r.id)+': '+r.reason);
if(accDecision.status==='calculated'&&b.depreciation&&m.depreciation?.adjustment){
acceleratedDepreciation=calculateNormalDepreciation(b.depreciation,source,{from:'2026-01-01',to:'2026-12-31'},[...b.rows,...(b.schedules?.rows??[]),...(b.costs?.rows??[])],false,new Set(accelerations.filter(r=>r.status==='calculated').map(r=>r.assetId)));
if(acceleratedDepreciation.adjustment===null)fail(accDecision,acceleratedDepreciation.pending.join(' '));
else additionalDeduction=subtractFractions(m.depreciation.adjustment,acceleratedDepreciation.adjustment);
}else if(accDecision.status==='calculated')fail(accDecision,'Reconciliação da amortização normal em falta.');
}
if(accDecision.status==='indeterminate')additionalDeduction=null;
const taxableProfit=m.taxableProfit&&additionalDeduction?subtractFractions(m.taxableProfit,additionalDeduction):null;
const base=b.base?calculateNormalBase(b.base,taxableProfit,b.year,b.schedules?.currentLossReference,!!m.periodsFx?.short):null;
const assessmentInput=coopDecision.status==='calculated'?{version:1 as const,treatment:'general_61_1' as const,reference:i.cooperative.qualification.reference}:b.assessment;
const assessment=assessmentInput?calculateNormalAssessment(assessmentInput,base?.taxableBase??null,{year:b.year,scope:b.scope,currency:m.currency,extended:!!b.schedules||!!b.periodsFx,short:!!m.periodsFx?.short,period:specialPeriod(b,m)}):null;
const normalColecta=assessment?.colecta??null,colecta=coopDecision.status==='indeterminate'?null:normalColecta?(coopDecision.status==='calculated'?mul(normalColecta,1n,2n):normalColecta):null;
const combinedColecta=colecta&&autonomousTax?addFractions([colecta,autonomousTax]):null;
return{input:structuredClone(i),context:structuredClone(specialContext(draft)),subjectNuit:b.base?.subjectNuit??'',period:specialPeriod(b,m),expenses:{...expenseDecision,rows:expenses,knownAutonomous,autonomousTax,source:specialSources.expenses},cooperative:{...coopDecision,rate:coopDecision.status==='calculated'?fraction(16n):null,source:specialSources.cooperative},acceleration:{...accDecision,rows:accelerations,additionalDeduction,normal:m.depreciation??null,accelerated:acceleratedDepreciation,source:specialSources.acceleration},reference:{taxableProfit:m.taxableProfit,taxableBase:m.taxableBase,colecta:m.colecta??null},taxableProfit,taxableBase:base?.taxableBase??null,colecta,combinedColecta,pending:[...expenseDecision.pending,...coopDecision.pending,...accDecision.pending,...(base?.pending??[]),...(assessment?.pending??[])],limitations:['L7 parcial:apenas61(4),cooperativa integralmente elegível12 eCBF16 no recorte documentado.','Localização/sector só contextualizam;não activam benefícios.','Parcelas mistas,cumulação,mais-valias e demais famílias têm correspondência própria.','M20/M22 permanecem preparaçãoL6 de referência;efeitosL7 sem campo oficial presumido.','Colecta combinada não é saldo final a pagar/recuperar;retenções,pagamentos e créditos anuais emL8.'],finalBalance:{scope:'L8',payable:null,recoverable:null}};
}
export type SpecialModel=ReturnType<typeof calculateSpecial>;
const money=(v:FiscalFraction|null)=>{if(!v)return'Indeterminado';const p=fractionPresentation(v);return(p.approximate?'≈':'')+p.decimal+' MZN (exacto '+v.numerator+'/'+v.denominator+')';};
const status=(s:Status)=>({calculated:'Calculado no recorte',absent:'Ausência declarada',not_applicable:'Não aplicável',indeterminate:'Informação em falta'})[s];
const contextDescription=(c:Record<string,unknown>)=>[['Sector','sector_id'],['Província','province_id'],['Distrito','district_id'],['Posto administrativo','admin_post_id'],['Localidade','locality_id']].map(([label,key])=>label+': '+String(c[key+'_label']||c[key]||'Por identificar')).join(';');
export function specialReportRows(m:SpecialModel):Array<[string,string,string,string]>{return[
['IRPC — L7','Qualificação comum',`NUIT:${m.subjectNuit};período:${m.period.from}–${m.period.to};${contextDescription(m.context)};${m.limitations.join(' ')}`,'Origem herdada conservada;fonte/condições/período por tratamento;sem concessão pela localização.'],
['IRPC — L7','Despesas — imposto autónomo',`${status(m.expenses.status)};parcela conhecida:${money(m.expenses.knownAutonomous)};imposto autónomo reconciliado:${money(m.expenses.autonomousTax)};${m.expenses.reason}`,`${m.input.expenses.qualification.reference};${m.input.expenses.qualification.periodReference};${m.expenses.source}`],
...m.expenses.rows.map(r=>['IRPC — L7',r.document+'/'+r.line,`${status(r.status)};natureza:${r.nature||'Por identificar'};despesa:${money(r.amount)};ajustamento36g já emL6:${money(r.l6Adjustment)};novo ajustamento ao lucro:${money(r.additionalProfitAdjustment)};taxa:${r.rate?'35%':'Não aplicada'};imposto autónomo:${money(r.tax)};${r.reason}`,r.reference]as[string,string,string,string]),
['IRPC — L7','Cooperativa — redução da taxa',`${status(m.cooperative.status)};tipo:${m.input.cooperative.kind||'Por identificar'};taxa:${m.cooperative.rate?'16%':'Não aplicada'};${m.cooperative.reason}`,`${m.input.cooperative.qualification.reference};${m.input.cooperative.qualification.periodReference};${m.cooperative.source}`],
['IRPC — L7','Amortizações aceleradas',`${status(m.acceleration.status)};dedução adicional conciliada:${money(m.acceleration.additionalDeduction)};${m.acceleration.reason}`,`${m.input.acceleration.qualification.reference};${m.input.acceleration.qualification.periodReference};${m.input.acceleration.recognitionReference};${m.acceleration.source}`],
...m.acceleration.rows.map(r=>{const a=m.acceleration.accelerated?.assets.find(a=>a.id===r.assetId),n=m.acceleration.normal?.assets.find(a=>a.id===r.assetId);return['IRPC — L7',r.description||r.assetId,`${status(r.status)};quota normal:${money(n?.quota??null)};quota acelerada:${money(a?.quota??null)};dedução normal:${money(n?.deduction??null)};dedução acelerada:${money(a?.deduction??null)};${r.reason}`,r.reference]as[string,string,string,string];}),
['IRPC — L7','Efeitos nos totais',`ReferênciaL6:lucro:${money(m.reference.taxableProfit)};base:${money(m.reference.taxableBase)};colecta:${money(m.reference.colecta)}. Após tratamentosL7:lucro:${money(m.taxableProfit)};base:${money(m.taxableBase)};colecta sobre a base:${money(m.colecta)};imposto autónomo:${money(m.expenses.autonomousTax)};colecta combinada:${money(m.combinedColecta)}. Saldo final a pagar/recuperar:Indeterminado (L8).`,m.pending.join(' | ')||'Regras/parcelas reconciliadas neste recorte;simulação,não liquidação final.'],
];}
+11 -11
View File
@@ -445,20 +445,25 @@ export function portalNavigation(access: PortalNavAccess): PortalNavItem[] {
id: 'discovery',
label: 'Descoberta',
children: [
link(
'why',
'Porquê investir em Moçambique?',
'/porque-investir',
),
link(
'idea-entry',
'Partir de uma ideia',
'/investimentos/iniciar',
),
link(
'why',
'Porquê investir em Moçambique',
'/porque-investir',
'opportunities',
'Consultar oportunidades',
'/oportunidades',
),
link(
'opportunities',
'Oportunidades de investimento',
'/oportunidades',
'simulator',
'Simulador Fiscal',
access.context?.simulator || '/simulador-fiscal',
),
link('sectors', 'Sectores de investimento', '/sectores'),
link('locations', 'Localizações', '/oportunidades?view=map'),
@@ -500,11 +505,6 @@ export function portalNavigation(access: PortalNavAccess): PortalNavItem[] {
label: 'Realização',
children: [
link('start', 'Iniciar investimento', '/investimentos/iniciar'),
link(
'simulator',
'Incentivos e simulador fiscal',
access.context?.simulator || '/simulador-fiscal',
),
link(
'licensing',
'Licenciamento',
@@ -178,6 +178,7 @@ const rowSection: Record<string, DossierReportSectionId> = {
ISPC: 'finance',
'IRPC — retenções': 'finance',
'IRPC normal — L6': 'finance',
'IRPC — L7': 'finance',
Equipa: 'team',
'Necessidade de negócio': 'resources',
Financiamento: 'resources',
-1
View File
@@ -1001,7 +1001,6 @@ export default function PortalInvestidorApp({
setQuery={setHeroQuery}
onSearch={handleHeroSearch}
stats={home.data?.data.stats}
onNavigate={navigate}
/>
<InvestmentContextCards />
<QueryStatus
+9 -1
View File
@@ -1,6 +1,7 @@
import { Head, Link, usePage } from '@inertiajs/react';
import type { ReactNode } from 'react';
import { PortalMenu } from '@/layouts/portal-navigation';
import { cn } from '@/lib/utils';
import type { TerritorialSourceEvidence } from '@/components/territorial-source-evidence';
import type {
StructureGeography,
@@ -101,9 +102,11 @@ export const card = 'rounded-xl border border-slate-200 bg-white p-5 shadow-sm';
export function Frame({
title,
children,
mainClassName,
}: {
title: string;
children: ReactNode;
mainClassName?: string;
}) {
const { flash } = usePage<{
flash?: { success?: string; warning?: string };
@@ -112,7 +115,12 @@ export function Frame({
<div className="min-h-screen bg-slate-50 text-slate-900">
<Head title={title} />
<PortalMenu />
<main className="mx-auto max-w-7xl space-y-6 px-5 py-9">
<main
className={cn(
'mx-auto max-w-7xl space-y-6 px-5 py-9',
mainClassName,
)}
>
<h1 className="text-3xl font-bold">{title}</h1>
{flash?.warning && (
<p
+198 -96
View File
@@ -1,99 +1,201 @@
import { Link } from '@inertiajs/react';
import { Frame, card, button } from '@/pages/investment/shared';
import { cn } from '@/lib/utils';
const compactCard = cn(card, 'p-4');
const compactButton = cn(button, 'min-h-11 px-3 py-1.5 text-sm sm:min-h-9');
export default function WhyInvest() {
return (
<Frame title="Porquê investir em Moçambique">
<section className={card + ' space-y-4'}>
<h2 className="text-2xl font-bold">
Encontrar possibilidades e avaliar as condições
</h2>
<p>
Investir começa por identificar uma necessidade, um mercado
e uma forma de criar valor. Em Moçambique, explore as
possibilidades de produção, transformação, logística,
turismo e serviços e compare as condições de cada projecto.
Este percurso destina-se a investidores nacionais e
estrangeiros, em todo o território nacional.
</p>
<p>
A informação do portal ajuda a comparar possibilidades e a
organizar os elementos do dossier. Uma página setorial ou
artigo educativo não representa uma oportunidade concreta
nem uma recomendação de retorno.
</p>
<div className="flex flex-wrap gap-3">
<Link className={button} href="/oportunidades">
Explorar oportunidades publicadas
</Link>
<Link className={button} href="/investimentos/iniciar">
Iniciar ou continuar uma ideia
</Link>
<Frame
title="Porquê investir em Moçambique?"
mainClassName="space-y-4 py-6"
>
<div className="flow-root">
<div className="-mx-2 flow-root">
<article
aria-label="Investir em Moçambique"
className="p-2 lg:float-left lg:w-2/3"
>
<div className="space-y-3 text-base leading-6 text-slate-700">
<p>
Investir em Moçambique é escolher um mercado em
forte expansão, estrategicamente posicionado na
África Austral e integrado na SADC, com acesso
directo a seis países vizinhos e a um dos
maiores blocos económicos da região. A
estabilidade política, a segurança e um ambiente
regulatório cada vez mais favorável tornam o
país um destino confiável e competitivo para
investidores nacionais e estrangeiros.
</p>
<p>
A localização privilegiada faz de Moçambique uma
plataforma logística natural. Os portos de
Maputo, Beira e Nacala — este último, o porto
natural mais profundo da costa oriental africana
— funcionam como corredores eficientes para
economias sem litoral como as de Malawi, Zâmbia
e Zimbabué. Esta infraestrutura sólida consolida
o país como um hub regional de comércio,
transporte e distribuição.
</p>
<p>
Moçambique reforça a confiança dos investidores
por meio de acordos bilaterais de investimento e
de tratados de dupla tributação com economias
estratégicas, garantindo estabilidade jurídica e
protecção aos investimentos. Além disso, oferece
incentivos fiscais e aduaneiros competitivos,
aliados ao acesso preferencial a grandes
mercados internacionais via AGOA (EUA), EBA
(União Europeia), preferências comerciais com a
China e parcerias com a Índia. Estes mecanismos
aumentam a competitividade das empresas que se
instalam no país e ampliam o seu alcance global.
</p>
<p>
O país oferece garantias essenciais, como
protecção da propriedade, repatriação livre de
lucros e incentivos específicos, incluindo
isenção de direitos aduaneiros para
equipamentos, crédito fiscal, depreciação
acelerada e benefícios para tecnologias,
formação, inovação e infraestruturas. Sectores
prioritários — agricultura, pescas, indústrias
rurais, turismo, mineração, petróleo e gás — bem
como zonas francas e zonas económicas especiais
dispõem de regimes particularmente vantajosos.
</p>
<p>
<strong>
Investir em Moçambique é integrar um país em
transformação
</strong>
, rico em recursos, com enorme potencial
energético, agricultura fértil, projectos
estruturantes em curso e uma visão clara de
industrialização. Com reformas consistentes,
vantagens logísticas e acesso preferencial a
mercados internacionais, o país destaca-se como
um dos destinos mais promissores para
investidores que buscam crescimento sustentável,
estabilidade e oportunidades concretas na África
Austral.
</p>
</div>
</article>
<div className="p-2 lg:inline-block lg:w-1/3 lg:align-top">
<section className={compactCard + ' space-y-3'}>
<h2 className="text-xl leading-snug font-bold">
Encontrar possibilidades e avaliar as condições
</h2>
<p>
Investir começa por identificar uma necessidade,
um mercado e uma forma de criar valor. Em
Moçambique, explore as possibilidades de
produção, transformação, logística, turismo e
serviços e compare as condições de cada
projecto. Este percurso destina-se a
investidores nacionais e estrangeiros, em todo o
território nacional.
</p>
<p>
A informação do portal ajuda a comparar
possibilidades e a organizar os elementos do
dossier. Uma página setorial ou artigo educativo
não representa uma oportunidade concreta nem uma
recomendação de retorno.
</p>
<div className="flex flex-wrap gap-2">
<Link
className={compactButton}
href="/oportunidades"
>
Explorar oportunidades publicadas
</Link>
<Link
className={compactButton}
href="/investimentos/iniciar"
>
Iniciar ou continuar uma ideia
</Link>
</div>
</section>
</div>
{[
[
'Produção e transformação',
'Compare fornecimento, processamento e comercialização. Avalie matérias-primas, fornecedores, energia, água e procura antes de escolher a escala do projecto.',
'/sectores',
],
[
'Território e ligações',
'Compare localizações, corredores e parques com o mercado que pretende servir. Confira acessos, logística, infra-estruturas e as condições documentadas de cada ficha.',
'/oportunidades?view=map',
],
[
'Serviços e parcerias',
'Explore necessidades de empresas e comunidades e possibilidades de cooperação. Distinga uma ideia a desenvolver de uma oportunidade publicada ou de uma parceria formalizada.',
'/parcerias',
],
].map(([title, text, href]) => (
<div
className="p-2 md:inline-block md:w-1/2 md:align-top lg:w-1/3"
key={title}
>
<article className={compactCard + ' space-y-2'}>
<h2 className="text-lg leading-snug font-bold">
{title}
</h2>
<p>{text}</p>
<Link className="underline" href={href}>
Explorar {title.toLowerCase()}
</Link>
</article>
</div>
))}
{[
[
'Sectores e modelos de negócio',
'Consulte o conteúdo educativo e as oportunidades cadastradas. Pode iniciar uma ideia mesmo sem um anúncio publicado.',
'/sectores',
],
[
'Localizações e enquadramentos',
'Explore o mapa e as fichas de corredores, clusters, zonas, parques e projectos. Cada referência conserva a natureza e o fundamento que lhe estão associados.',
'/oportunidades?view=map',
],
[
'Fontes para decidir',
'Consulte documentos e legislação do acervo publicado. Confirme o âmbito e o período aplicável antes de usar uma informação no seu processo.',
'/documentos',
],
[
'Um dossier para desenvolver a ideia',
'A oportunidade, o sector e a localização convergem num dossier com cinco fases e 19 etapas. A orientação permite preparar etapas em paralelo e respeita a aplicabilidade de terra e licenciamento.',
'/como-investir',
],
].map(([title, text, href]) => (
<div
className="p-2 md:inline-block md:w-1/2 md:align-top lg:w-1/3"
key={title}
>
<article className={compactCard + ' space-y-2'}>
<h2 className="text-lg leading-snug font-bold">
{title}
</h2>
<p>{text}</p>
<Link className="underline" href={href}>
Consultar {title.toLowerCase()}
</Link>
</article>
</div>
))}
</div>
</section>
<section
aria-label="Perspectivas para avaliar o investimento"
className="grid gap-4 md:grid-cols-3"
>
{[
[
'Produção e transformação',
'Compare fornecimento, processamento e comercialização. Avalie matérias-primas, fornecedores, energia, água e procura antes de escolher a escala do projecto.',
'/sectores',
],
[
'Território e ligações',
'Compare localizações, corredores e parques com o mercado que pretende servir. Confira acessos, logística, infra-estruturas e as condições documentadas de cada ficha.',
'/oportunidades?view=map',
],
[
'Serviços e parcerias',
'Explore necessidades de empresas e comunidades e possibilidades de cooperação. Distinga uma ideia a desenvolver de uma oportunidade publicada ou de uma parceria formalizada.',
'/parcerias',
],
].map(([title, text, href]) => (
<article className={card + ' space-y-3'} key={title}>
<h2 className="text-xl font-bold">{title}</h2>
<p>{text}</p>
<Link className="underline" href={href}>
Explorar {title.toLowerCase()}
</Link>
</article>
))}
</section>
<section className="grid gap-4 md:grid-cols-2">
{[
[
'Sectores e modelos de negócio',
'Consulte o conteúdo educativo e as oportunidades cadastradas. Pode iniciar uma ideia mesmo sem um anúncio publicado.',
'/sectores',
],
[
'Localizações e enquadramentos',
'Explore o mapa e as fichas de corredores, clusters, zonas, parques e projectos. Cada referência conserva a natureza e o fundamento que lhe estão associados.',
'/oportunidades?view=map',
],
[
'Fontes para decidir',
'Consulte documentos e legislação do acervo publicado. Confirme o âmbito e o período aplicável antes de usar uma informação no seu processo.',
'/documentos',
],
[
'Um dossier para desenvolver a ideia',
'A oportunidade, o sector e a localização convergem num dossier com cinco fases e 19 etapas. A orientação permite preparar etapas em paralelo e respeita a aplicabilidade de terra e licenciamento.',
'/como-investir',
],
].map(([title, text, href]) => (
<article className={card + ' space-y-3'} key={title}>
<h2 className="text-xl font-bold">{title}</h2>
<p>{text}</p>
<Link className="underline" href={href}>
Consultar {title.toLowerCase()}
</Link>
</article>
))}
</section>
<section className={card + ' space-y-3'}>
<h2 className="text-xl font-bold">
</div>
<section className={compactCard + ' space-y-2'}>
<h2 className="text-lg leading-snug font-bold">
Preparar condições, documentação e apoio
</h2>
<p>
@@ -109,7 +211,7 @@ export default function WhyInvest() {
retorno do investimento. Informação desconhecida deve
continuar identificada como tal.
</p>
<div className="flex flex-wrap gap-4">
<div className="flex flex-wrap gap-x-3 gap-y-2">
<Link className="underline" href="/legislacao">
Legislação e enquadramento
</Link>
@@ -121,8 +223,8 @@ export default function WhyInvest() {
</Link>
</div>
</section>
<section className={card + ' space-y-3'}>
<h2 className="text-xl font-bold">
<section className={compactCard + ' space-y-2'}>
<h2 className="text-lg leading-snug font-bold">
Apoio ao longo do percurso
</h2>
<p>
@@ -131,8 +233,8 @@ export default function WhyInvest() {
distinto de submeter um pedido; uma comunicação interna não
equivale a uma decisão oficial.
</p>
<div className="flex flex-wrap gap-4">
<Link className={button} href="/balcao-virtual">
<div className="flex flex-wrap gap-x-3 gap-y-2">
<Link className={compactButton} href="/balcao-virtual">
Serviços ao investidor
</Link>
<Link className="underline" href="/apoio">
+64
View File
@@ -0,0 +1,64 @@
<?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 IrpcSpecialDraftTest extends TestCase
{
use DatabaseTransactions;
public function test_special_treatments_recover_with_original_plan_history_and_indeterminate_cases(): 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()]));
$id=null;$etag=null;
foreach(['expense','missing','negative','absent','cooperative','acceleration'] as $case){
$d=json_decode(file_get_contents(base_path('outputs/irpc-l7-common/'.$case.'.json')),true,flags:JSON_THROW_ON_ERROR);
$personal=['person_type'=>$d['person_type']];unset($d['person_type']);
if($id===null)$id=$this->postJson('/api/v1/simulation-drafts',['personal_snapshot'=>$personal,'economic_snapshot'=>$d],['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id');
else $this->putJson('/api/v1/simulation-drafts/'.$id,['personal_snapshot'=>$personal,'economic_snapshot'=>$d],['If-Match'=>$etag])->assertOk();
$r=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk();$etag=$r->headers->get('ETag');$back=$r->json('data.economic_snapshot');
$this->assertSame($d['business_plan_snapshot'],$back['business_plan_snapshot']);
$this->assertSame($d['modelo_a_snapshot'],$back['modelo_a_snapshot']);
$s=json_decode($back['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);$b=$s['irpcNormal'][$d['context_opportunity']];$m=$b['result']['model'];$l7=$m['special'];
$this->assertSame('IRPC-normal-adjustments/10',$m['version']);
$this->assertSame($b['special'],$l7['input']);
$this->assertContains('IRPC-normal-adjustments/9',array_column(array_column($b['history'],'model'),'version'));
$this->assertArrayHasKey('irpcWithholdings',$s);$this->assertArrayHasKey('books',$s);
$this->assertNull($m['tax']);$this->assertNull($l7['finalBalance']['payable']);$this->assertNull($l7['finalBalance']['recoverable']);
$this->assertSame('123456789',$l7['subjectNuit']);
$this->assertStringContainsString('61(4)',$l7['expenses']['source']);
if($case==='expense'){
$this->assertSame('35',$l7['expenses']['autonomousTax']['numerator']);
$this->assertSame('100',$l7['expenses']['rows'][0]['l6Adjustment']['numerator']);
$this->assertSame('0',$l7['expenses']['rows'][0]['additionalProfitAdjustment']['numerator']);
$this->assertSame($m['taxableProfit'],$l7['taxableProfit']);
$this->assertSame(['numerator'=>'5343','denominator'=>'5'],$l7['combinedColecta']);
}elseif($case==='missing'){
$this->assertSame('indeterminate',$l7['expenses']['status']);$this->assertNull($l7['expenses']['autonomousTax']);$this->assertNull($l7['combinedColecta']);
$this->assertSame('3230',$m['taxableProfit']['numerator']);
}elseif($case==='negative'){
$this->assertSame('not_applicable',$l7['expenses']['rows'][0]['status']);$this->assertSame('0',$l7['expenses']['autonomousTax']['numerator']);
}elseif($case==='absent'){
$this->assertSame('absent',$l7['expenses']['status']);$this->assertSame('0',$l7['expenses']['autonomousTax']['numerator']);
}elseif($case==='cooperative'){
$this->assertSame('16',$l7['cooperative']['rate']['numerator']);$this->assertSame(['numerator'=>'2504','denominator'=>'5'],$l7['colecta']);
$this->assertSame(['numerator'=>'5008','denominator'=>'5'],$m['colecta']);
}else{
$this->assertSame('20',$l7['acceleration']['additionalDeduction']['numerator']);
$this->assertSame('150',$l7['acceleration']['accelerated']['assets'][0]['quota']['numerator']);
$this->assertSame('120',$l7['acceleration']['accelerated']['assets'][0]['deduction']['numerator']);
$this->assertSame('6240',$l7['taxableProfit']['numerator']);$this->assertSame('6260',$m['taxableProfit']['numerator']);
$this->assertSame($b['depreciation'],$l7['acceleration']['accelerated']['input']);
}
file_put_contents(base_path('outputs/irpc-l7-common/recovered-'.$case.'.json'),json_encode($back,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE));
}
}
}
File diff suppressed because one or more lines are too long
+32
View File
@@ -0,0 +1,32 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {normalBook,normalCurrent,calculateNormal,recordNormal,saveNormalBook,normalHtml} from '../../resources/js/lib/irpc-normal.ts';
import {newSpecialInput,newQualification,newSpecialExpense,newAcceleratedAsset} from '../../resources/js/lib/irpc-special.ts';
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
const seed=()=>JSON.parse(fs.readFileSync(new URL('./fixtures/irpc-l6-values-preserved.json',import.meta.url),'utf8'));
const value=v=>v?Number(v.numerator)/Number(v.denominator):null;
const qualification=(state='absent',from='2026-07-01',to='2026-12-31')=>({...newQualification(),state,eligible:state==='known'?'yes':'',from,to,reference:'QA declaração/prova das condições legais no sujeito e parcela,sem inferência territorial',periodReference:'QA norma/exercício2026 e período documentado'});
function setup(){const d=seed(),b=normalBook(d);b.special=newSpecialInput();for(const part of[b.special.expenses,b.special.cooperative,b.special.acceleration])part.qualification=qualification();return{d,b};}
function expenses(){const{d,b}=setup();b.schedules.rows.push({id:'expense36g',rule:'undocumented',amount:'100',sourceCode:'operating_expenses',document:'QA-despesa',line:'1',reference:'QA despesa100 efectivamente incluída e não documentada36g',fiscalYear:'',conditions:'yes'});b.profit.topics.expenseCorrections={state:'known',amount:'100',reference:'QA acréscimo36g já conferido,sem outra correcção'};b.special.expenses.qualification=qualification('known');b.special.expenses.rows=[{...newSpecialExpense('autonomous1'),scheduleId:'expense36g',nature:'undocumented',eligible:'yes',reference:'QA qualificação legal61(4),não inferida de anexo em falta'}];return{d,b};}
function cooperative(){const{d,b}=setup();b.special.cooperative={qualification:qualification('known'),kind:'agrarian',allIncomeEligible:'yes',withheldIncome:'absent'};return{d,b};}
function acceleration(){const{d,b}=setup();delete b.periodsFx;delete b.forms;b.schedules.interest.amount='240';Object.assign(b.depreciation.assets[0],{category:'machine',description:'Máquina industrial existente QA',cost:'1000',rate:'10',accounting:'120',start:'2026-01-01',timing:'annual'});for(const part of[b.special.expenses,b.special.cooperative,b.special.acceleration])part.qualification=qualification('absent','2026-01-01','2026-12-31');b.special.acceleration={qualification:qualification('known','2026-01-01','2026-12-31'),cbfRequirements:'yes',recognition:'documented',recognitionReference:'QA instrumento do projecto/reconhecimento10,pressupostos3/9 e afectação industrial documentados',noOtherBenefits:'yes',rows:[{...newAcceleratedAsset('accelerated1'),assetId:b.depreciation.assets[0].id,kind:'industrial_equipment',eligible:'yes',reference:'QA factura/afectação da máquina ao projecto industrialCBF16'}]};return{d,b};}
test('no optionalL7 keeps exact accepted9 result and key; installed history is not recalculated on read',()=>{const d=seed(),b=normalBook(d),old=structuredClone(b.result);assert.equal(normalCurrent(d,b),true);assert.deepEqual(calculateNormal(d,b),old.model);assert.deepEqual(normalBook(d).result,old);});
test('61(4) reuses100 addback36g and computes35 autonomously without another profit adjustment',()=>{const{d,b}=expenses(),m=calculateNormal(d,b),s=m.special;assert.equal(m.version,'IRPC-normal-adjustments/10');assert.equal(value(m.taxableProfit),3230);assert.equal(value(m.colecta),1033.6);assert.equal(value(s.taxableProfit),3230);assert.equal(value(s.expenses.rows[0].l6Adjustment),100);assert.equal(value(s.expenses.rows[0].additionalProfitAdjustment),0);assert.equal(value(s.expenses.autonomousTax),35);assert.equal(value(s.combinedColecta),1068.6);assert.equal(s.finalBalance.payable,null);});
test('missing, absent and notapplicable differ; attachment presence alone never classifies an expense',()=>{const{d,b}=setup();b.special.expenses.qualification=qualification('');let s=calculateNormal(d,b).special;assert.equal(s.expenses.status,'indeterminate');assert.equal(s.expenses.autonomousTax,null);b.special.expenses.qualification=qualification('absent');s=calculateNormal(d,b).special;assert.equal(s.expenses.status,'absent');assert.equal(value(s.expenses.autonomousTax),0);b.special.expenses.qualification=qualification('not_applicable');assert.equal(calculateNormal(d,b).special.expenses.status,'not_applicable');const c=expenses();c.b.special.expenses.rows[0].nature='';assert.equal(calculateNormal(c.d,c.b).special.expenses.autonomousTax,null);});
test('false condition keeps existing addback and no autonomous tax; contradictory absence cannot erase expense',()=>{const{d,b}=expenses();b.special.expenses.rows[0].eligible='no';let m=calculateNormal(d,b);assert.equal(m.special.expenses.rows[0].status,'not_applicable');assert.equal(value(m.special.expenses.autonomousTax),0);assert.equal(value(m.taxableProfit),3230);b.special.expenses.rows=[];b.special.expenses.qualification=qualification('absent');m=calculateNormal(d,b);assert.equal(m.special.expenses.status,'indeterminate');assert.equal(value(m.taxableProfit),3230);});
test('duplicate, unlinked or uncalculated36g cannot doublecharge or manufacture tax',()=>{for(const mode of['duplicate','unlinked','uncalculated','missingcoverage']){const{d,b}=expenses();if(mode==='duplicate')b.special.expenses.rows.push({...b.special.expenses.rows[0],id:'duplicate'});if(mode==='unlinked')b.special.expenses.rows[0].scheduleId='not-found';if(mode==='uncalculated')b.schedules.rows[0].conditions='';if(mode==='missingcoverage')b.special.expenses.rows=[];assert.equal(calculateNormal(d,b).special.expenses.autonomousTax,null,mode);}});
test('common qualification rejects wrong period/year or missing identity without blocking independent L6 totals',()=>{for(const mutate of[b=>b.special.expenses.qualification.to='2025-12-31',b=>b.special.expenses.qualification.periodReference='',b=>b.base.subjectNuit='']){const{d,b}=expenses();mutate(b);const m=calculateNormal(d,b);assert.equal(m.special.expenses.autonomousTax,null);if(b.base.subjectNuit)assert.equal(value(m.colecta),1033.6);}});
test('unknown benefit does not suppress separately calculable autonomous expense or normal reference',()=>{const{d,b}=expenses();b.special.acceleration.qualification=qualification('');const m=calculateNormal(d,b);assert.equal(value(m.special.expenses.autonomousTax),35);assert.equal(value(m.special.reference.colecta),1033.6);assert.equal(m.special.combinedColecta,null);});
test('eligible cooperative uses16percent without changing reference32percent or autonomous expense rate',()=>{const{d,b}=cooperative(),m=calculateNormal(d,b);assert.equal(value(m.colecta),1001.6);assert.equal(m.special.cooperative.status,'calculated');assert.equal(value(m.special.cooperative.rate),16);assert.equal(value(m.special.colecta),500.8);assert.equal(value(m.special.taxableBase),3130);assert.equal(value(m.special.combinedColecta),500.8);const x=expenses();x.b.special.cooperative=structuredClone(b.special.cooperative);assert.equal(value(calculateNormal(x.d,x.b).special.combinedColecta),551.8);});
test('mixed, withheld, unclassified or false cooperative conditions never grant blanket reduction',()=>{for(const mutate of[c=>c.allIncomeEligible='no',c=>c.withheldIncome='known',c=>c.kind='other']){const{d,b}=cooperative();mutate(b.special.cooperative);const m=calculateNormal(d,b);assert.equal(m.special.cooperative.status,'indeterminate');assert.equal(m.special.colecta,null);assert.equal(value(m.colecta),1001.6);}const{d,b}=cooperative();b.special.cooperative.qualification.eligible='no';assert.equal(value(calculateNormal(d,b).special.colecta),1001.6);});
test('cooperative treatment does not require mislabelling special rate as L6 general; contradictory absence remains pending',()=>{const{d,b}=cooperative();b.assessment.treatment='other';let m=calculateNormal(d,b);assert.equal(m.colecta,null);assert.equal(value(m.special.colecta),500.8);b.special.cooperative.qualification=qualification('absent');m=calculateNormal(d,b);assert.equal(m.special.cooperative.status,'indeterminate');assert.equal(m.special.colecta,null);});
test('common period follows declared shortperiod even without schedules; calendar dates cannot replace it',()=>{const{d,b}=cooperative();delete b.schedules;b.special.expenses.qualification=qualification('absent','2026-01-01','2026-12-31');const m=calculateNormal(d,b);assert.equal(m.special.period.from,'2026-07-01');assert.equal(m.special.expenses.status,'indeterminate');});
test('CBF16 reuses asset and rate10to15 but respects120 accounted cap; additional deduction20 not50',()=>{const{d,b}=acceleration(),input=JSON.stringify(b.depreciation),m=calculateNormal(d,b),s=m.special;assert.equal(s.acceleration.status,'calculated',s.acceleration.reason);assert.equal(value(m.depreciation.assets[0].quota),100);assert.equal(value(s.acceleration.accelerated.assets[0].quota),150);assert.equal(value(s.acceleration.accelerated.assets[0].deduction),120);assert.equal(value(s.acceleration.additionalDeduction),20);assert.equal(value(m.taxableProfit),6260);assert.equal(value(s.taxableProfit),6240);assert.equal(value(s.taxableBase),6240);assert.equal(value(s.colecta),1996.8);assert.equal(JSON.stringify(b.depreciation),input);});
test('new project building reuses land separation and legal table rate before bounded acceleration',()=>{const{d,b}=acceleration();Object.assign(b.depreciation.assets[0],{category:'commercial_building',cost:'5000',land:'0',rate:'2'});b.special.acceleration.rows[0].kind='new_project_building';const m=calculateNormal(d,b);assert.equal(m.special.acceleration.status,'calculated');assert.equal(value(m.special.acceleration.accelerated.assets[0].quota),150);assert.equal(value(m.special.acceleration.additionalDeduction),20);});
test('lower optional normal quota remains valid L6 but is not treated as legally fixed rate in CBF16',()=>{const{d,b}=acceleration();b.depreciation.assets[0].rate='5';const m=calculateNormal(d,b);assert.equal(m.depreciation.assets[0].status,'calculated');assert.equal(m.special.acceleration.additionalDeduction,null);assert.match(m.special.acceleration.reason,/quota inferior/);});
test('location alone, wrong activity, prior quotas, unsupported periods and benefit combinations cannot accelerate',()=>{for(const mutate of[b=>b.special.acceleration.cbfRequirements='',b=>b.special.acceleration.recognitionReference='',b=>b.special.acceleration.rows[0].kind='other',b=>b.depreciation.assets[0].timing='months',b=>b.depreciation.assets[0].previousAccounting='1',b=>b.special.acceleration.noOtherBenefits='no',b=>{b.special.cooperative={qualification:qualification('known','2026-01-01','2026-12-31'),kind:'agrarian',allIncomeEligible:'yes',withheldIncome:'absent'};}]){const{d,b}=acceleration();d.province_id='ZEE-candidate';mutate(b);const m=calculateNormal(d,b);assert.equal(m.special.acceleration.additionalDeduction,null);assert.notEqual(m.taxableProfit,null);assert.equal(m.special.acceleration.status,'indeterminate');}});
test('save/recover/report preserves9history and L5/books; repeated calculation never accumulates tax or asset deduction',()=>{const{d,b}=expenses(),old=structuredClone(b.result),plan=d.business_plan_snapshot;d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,b,'2026-10-26T14:00:00+02:00'));let back=normalBook(JSON.parse(JSON.stringify(d)));assert.equal(normalCurrent(d,back),true);assert.deepEqual(back.history.at(-1),old);assert.equal(d.business_plan_snapshot,plan);assert.ok(JSON.parse(d.modelo_a_snapshot).irpcWithholdings);const html=normalHtml(d);assert.match(html,/imposto autónomo:35/);assert.match(html,/novo ajustamento ao lucro:0/);assert.match(html,/Saldo final a pagar\/recuperar:Indeterminado/);assert.match(JSON.stringify(createProjectDossierReport(d,{selectedSections:new Set(['finance'])})),/Despesas — imposto autónomo/);d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,back));back=normalBook(d);assert.equal(value(back.result.model.special.expenses.autonomousTax),35);assert.equal(value(back.result.model.taxableProfit),3230);d.province_id='changed';assert.equal(normalCurrent(d,normalBook(d)),false);assert.throws(()=>normalHtml(d),/Calcule/);});
test('new evidence changes key; malformedqualification or duplicate row ID cannot overwrite book',()=>{const{d,b}=expenses();d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,b));const back=normalBook(d);back.special.expenses.rows[0].reference+=' alterado';assert.equal(normalCurrent(d,back),false);back.special.expenses.rows.push(structuredClone(back.special.expenses.rows[0]));assert.throws(()=>saveNormalBook(d,back),/identificador repetido/);});
test('report presents context labels and retains provenance internally without dumping raw context snapshots',()=>{const{d,b}=setup();d.province_id_label='Província QA';d.context_opportunity_snapshot='{"internal":"QA implementation blob"}';d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,b));assert.match(normalHtml(d),/Província: Província QA/);assert.doesNotMatch(normalHtml(d),/QA implementation blob/);assert.equal(normalBook(d).result.model.special.context.context_opportunity_snapshot,d.context_opportunity_snapshot);});
test('write only new QA cases for transactional API and recovered reports',()=>{const missing=expenses(),negative=expenses();missing.b.special.expenses.rows[0].nature='';negative.b.special.expenses.rows[0].eligible='no';const cases={expense:expenses(),missing,negative,absent:setup(),cooperative:cooperative(),acceleration:acceleration()};fs.mkdirSync('outputs/irpc-l7-common',{recursive:true});for(const[name,{d,b}]of Object.entries(cases)){d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,b,'2026-10-26T14:00:00+02:00'));fs.writeFileSync('outputs/irpc-l7-common/'+name+'.json',JSON.stringify(d));fs.writeFileSync('outputs/irpc-l7-common/'+name+'.html',normalHtml(d));}});
+1 -1
View File
@@ -100,7 +100,7 @@ void test('reconciled navigation selects discovery, realization and private supp
);
assert.equal(
currentNavigationGroup(groups, '/simulador-fiscal'),
'realization',
'discovery',
);
assert.equal(
currentNavigationGroup(groups, '/balcao-virtual/dossiers/fixture'),
+21
View File
@@ -0,0 +1,21 @@
<?php
$root=dirname(__DIR__);
$operation=$argv[1]??'';
if(!in_array($operation,['routes','test'],true)||basename($root)!=='portal-investidor-irpc-l7-common-qa-20261026')throw new RuntimeException('Explicit L7 QA workspace and routes/test operation required.');
foreach(['storage/framework/views','storage/framework/cache','storage/framework/sessions','bootstrap/cache','storage/logs','outputs/irpc-l7-common']as$dir)if(!is_dir($root.'/'.$dir))mkdir($root.'/'.$dir,0700,true);
foreach(['APP_BASE_PATH'=>$root,'APP_ENV'=>'testing','APP_KEY'=>'base64:'.base64_encode(str_repeat('Q',32)),'DB_CONNECTION'=>'pgsql','DB_HOST'=>'127.0.0.1','DB_PORT'=>'55441','DB_DATABASE'=>'simulator_fiscal_delta_20261021_test','DB_USERNAME'=>'postgres','DB_PASSWORD'=>'','DB_URL'=>'','CACHE_STORE'=>'array','SESSION_DRIVER'=>'array','QUEUE_CONNECTION'=>'sync','MAIL_MAILER'=>'array'] as $k=>$v){putenv($k.'='.$v);$_ENV[$k]=$_SERVER[$k]=$v;}
$loader=require $root.'/vendor/autoload.php';
spl_autoload_register(function($class)use($root){foreach(['App\\'=>'app/','Tests\\'=>'tests/','Database\\Factories\\'=>'database/factories/']as$prefix=>$dir){if(str_starts_with($class,$prefix)){$file=$root.'/'.$dir.str_replace('\\','/',substr($class,strlen($prefix))).'.php';if(is_file($file)){require $file;return;}}}},true,true);
$app=require $root.'/bootstrap/app.php';
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);
(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
$c=config('database.connections.pgsql');
if($app->configurationIsCached()||$c['host']!=='127.0.0.1'||(int)$c['port']!==55441||$c['database']!=='simulator_fiscal_delta_20261021_test'||!empty($c['url']))throw new RuntimeException('QA guard');
$pdo=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$c['database'],$c['username'],$c['password']);
if($pdo->query('select current_database()')->fetchColumn()!==$c['database'])throw new RuntimeException('QA identity');
if($operation==='routes'){
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$status=Illuminate\Support\Facades\Artisan::call('wayfinder:generate',['--with-form'=>true]);
echo Illuminate\Support\Facades\Artisan::output();exit($status);
}
$argv=['phpunit','-c','phpunit.investmoz.xml','tests/Feature/IrpcSpecialDraftTest.php'];$argc=count($argv);$_SERVER['argv']=$argv;$_SERVER['argc']=$argc;require $root.'/vendor/phpunit/phpunit/phpunit';