Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c0cb25cea | ||
|
|
3dda7130ee | ||
|
|
6af7092e83 | ||
|
|
49b448eb47 |
@@ -27258,5 +27258,160 @@
|
||||
},
|
||||
"P084_P085": "closed",
|
||||
"positive_field06_case": "not demonstrated;see receipt"
|
||||
},
|
||||
"l3_additional_prepared_20261025": {
|
||||
"status": "prepared_compatible_not_installed",
|
||||
"candidate": "0f4df8a4d1cfd0d7b788e58d7f6af8d385384d82",
|
||||
"source_QA": "b189d0fa",
|
||||
"baseline": "7ad187f9",
|
||||
"report": "docs/investmoz/simulations/l3-additional-delivery-20261025.json",
|
||||
"fresh_authenticated_backup_restore": "required at execution;not yet performed",
|
||||
"next": "L4ISPCaccordingtoexistingplan;L3remainingvisible",
|
||||
"superseded_by": "l3_additional_delivered_20261025",
|
||||
"installed_followup": "fa32a2b9"
|
||||
},
|
||||
"ispc_l4a_eligibility_qa_20261025": {
|
||||
"status": "QA_partial_eligibility_and_separate_option_not_installed",
|
||||
"report": "docs/investmoz/simulations/ispc-l4a-eligibility-qa-20261025.json",
|
||||
"tests": "12 new frontend passed;types/build exit0",
|
||||
"remaining": [
|
||||
"Apuramento trimestral e aplicação dos escalões3/4/5%,serviços12%,liberal15%,excesso20% e actividades mistas8; identificar correspondência exacta anual/trimestral antes do cálculo.",
|
||||
"Mínimo trimestral500 e obrigação declarativa; retenção5% nas aquisições ocasionais próprias,limite2.500.000 e modelo; sem reutilizar taxa deIVA.",
|
||||
"Percurso ocasional3(3–4),formalidades,modelos e prazos do regulamento aplicável; conferir apenas correspondências concretas necessárias,sem nova validação genérica.",
|
||||
"Demonstração visual integrada e gravação privada deste incremento antes de propor entregaL4."
|
||||
],
|
||||
"active_changes": false
|
||||
},
|
||||
"ispc_l4_quarterly_qa_20261025": {
|
||||
"status": "QA_demonstrated_eligibility_option_quarter_calculation_private_recovery_and_report_not_installed",
|
||||
"report": "docs/investmoz/simulations/ispc-l4-quarterly-qa-20261025.json",
|
||||
"example": {
|
||||
"context": "opportunity:375;SYNTHETIC QA",
|
||||
"option": "documentada2026-01-01",
|
||||
"quarter": "2026/T2",
|
||||
"prior_turnover_MZN": "100000",
|
||||
"quarter_base_MZN": "200000",
|
||||
"rate_percent": 12,
|
||||
"tax_MZN": "24000",
|
||||
"payment_MZN": "24000",
|
||||
"declaration": "mantida",
|
||||
"other_fiscal_books": "exactamente preservados"
|
||||
},
|
||||
"remaining_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
],
|
||||
"active_changes": false
|
||||
},
|
||||
"l3_additional_delivered_20261025": {
|
||||
"status": "installed_and_delta_verified",
|
||||
"requested": "0f4df8a4",
|
||||
"installed": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"test_only_descendant": true,
|
||||
"backup_tables": 174,
|
||||
"backup_files": 369,
|
||||
"restore_verified": true,
|
||||
"runtime_files_verified": 12,
|
||||
"changed_tables": {
|
||||
"cache": {
|
||||
"before": {
|
||||
"rows": 106,
|
||||
"checksum": "8ba41882cd8a7068c45619b3234af395"
|
||||
},
|
||||
"after": {
|
||||
"rows": 106,
|
||||
"checksum": "e2140cc9610defc5e64743159fb4df57"
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"before": {
|
||||
"rows": 153,
|
||||
"checksum": "66a8c21d1167a5c4ef27e205006736d4"
|
||||
},
|
||||
"after": {
|
||||
"rows": 154,
|
||||
"checksum": "6bd8d1311dcc20736dacc02873316399"
|
||||
}
|
||||
}
|
||||
},
|
||||
"report": "docs/investmoz/simulations/l3-additional-delivery-20261025.json",
|
||||
"L3": "open_specific_balance_preserved",
|
||||
"L4": "QA only;habitualquarterlypathdemonstrated"
|
||||
},
|
||||
"ispc_l4_prepared_delivery_20261025": {
|
||||
"status": "prepared_for_Git_delivery_not_installed",
|
||||
"candidate": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"baseline": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"feature_ref": "refs/heads/codex/ispc-l4-quarterly-qa-20261025",
|
||||
"runtime_files": 9,
|
||||
"compiled_markers": 12,
|
||||
"QA_proofs": "reused;no new functional round",
|
||||
"backup_restore": "fresh execution still required",
|
||||
"main_or_active_changed": false,
|
||||
"report": "docs/investmoz/simulations/ispc-l4-prepared-delivery-20261025.json",
|
||||
"remaining_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
],
|
||||
"superseded_by": "ispc_l4_delivered_20261025"
|
||||
},
|
||||
"ispc_l4_delivered_20261025": {
|
||||
"status": "installed_scoped_habitual_quarterly_ISPC_and_delta_verified",
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"previous": "fa32a2b9",
|
||||
"report": "docs/investmoz/simulations/ispc-l4-delivery-20261025.json",
|
||||
"restore_verified": true,
|
||||
"tables": 174,
|
||||
"files": 369,
|
||||
"L3_preserved": true,
|
||||
"ISPC_integrally_completed": false,
|
||||
"remaining_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
]
|
||||
},
|
||||
"ispc_residuals_grouped_QA_20261025": {
|
||||
"status": "QA_grouped_compatible_delta_not_installed",
|
||||
"report": "docs/investmoz/simulations/ispc-residuals-qa-20261025.json",
|
||||
"new_tests": 19,
|
||||
"API": "1/22",
|
||||
"active_changes": false,
|
||||
"remaining_calculations": [
|
||||
{
|
||||
"item": "Juros compensatórios",
|
||||
"state": "montante documentado pode ser conservado;fórmula ainda não implementada",
|
||||
"needed": "regra/taxa/base/período/dias efectivamente aplicáveis,no documento/instrução correspondente;sem zero ou taxa presumidos"
|
||||
},
|
||||
{
|
||||
"item": "Outros enquadramentos da parcela excedente",
|
||||
"state": "sem fórmula genérica;casos diferentes do acto isolado qualificado não recebem taxa automática",
|
||||
"needed": "natureza,regime do fornecedor,opção aplicável,base e suporte concretos;encaminhar para o cálculo próprio quando for outro regime,não bloquear o caso positivo implementado"
|
||||
}
|
||||
],
|
||||
"external_formal_dependencies": [
|
||||
{
|
||||
"item": "Quadro2doB–Geral",
|
||||
"needed": "correspondência concreta do mês/ano a inscrever para o trimestre;comunicado fornece meses de pagamento,que não são copiados automaticamente para período"
|
||||
},
|
||||
{
|
||||
"item": "Dispensa inferior500MZN noB–Geral",
|
||||
"needed": "Representação declarativa do imposto apurado com prestação dispensada10-A;sem preencher montanteapurado comozero porpresunção. O cálculo imposto/prestação jáestá implementado."
|
||||
},
|
||||
{
|
||||
"item": "Entrega de retenções",
|
||||
"needed": "modelo/código/instrução próprios12(3)ISPCe57(2k)IRPS;B–Geraldeapoio nãoéapresentadocomocorrespondênciacompletadestasretenções"
|
||||
},
|
||||
{
|
||||
"item": "Regulamentação2026/instruções de envio de facturas",
|
||||
"needed": "texto/exemplar/instrução concreta quando disponibilizado;comunicado transitório já implementado,não se mantém pesquisa genérica como aprovação adicional"
|
||||
},
|
||||
{
|
||||
"item": "Submissão e pagamento",
|
||||
"needed": "actos externos e comprovativos reais;nenhuma operaçãoATfoiexecutadaemQA"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
{
|
||||
"status": "installed_scoped_habitual_quarterly_ISPC_and_delta_verified",
|
||||
"authorization": "Tempo25/10:concluir instalação6af7092e peloGit combackup/restaurofresco,conferirdelta,preservarL3eprovasaceites;ISPCnãoéintegralmenteconcluído.",
|
||||
"candidate_installed": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"previous_installed": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"prepared_receipt": "ispc-l4-prepared-delivery-20261025.json",
|
||||
"authenticated_preflight": {
|
||||
"free_bytes": 7635865600,
|
||||
"existing_pipeline_minimum_bytes": 5368709120,
|
||||
"space_guard_satisfied": true,
|
||||
"installed": {
|
||||
"status": "installed",
|
||||
"commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"release": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/7ad187f9f0745245268e3ed5317547a96b4700f3-066618f1",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0
|
||||
},
|
||||
"current_link": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"release_revision": {
|
||||
"commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"branch": "main",
|
||||
"built_at": "2026-10-25T15:12:37.806036+00:00",
|
||||
"manifest_sha256": "cddac25dc66b3e555f2380cf3a9d4b2da6501cd03927c183c832a05b0ee5c993"
|
||||
},
|
||||
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
|
||||
"configuration_keys": [
|
||||
"repository",
|
||||
"branch",
|
||||
"target_url",
|
||||
"legacy_root",
|
||||
"state_root",
|
||||
"release_root",
|
||||
"current_link",
|
||||
"shared_assets",
|
||||
"php",
|
||||
"schema_contract",
|
||||
"ci_environment",
|
||||
"postgis_image",
|
||||
"test_database",
|
||||
"qa_port",
|
||||
"retention",
|
||||
"webhook_secret_file"
|
||||
],
|
||||
"safe_paths": {
|
||||
"repository": "nala/Investidor-V2",
|
||||
"release_root": "/var/www/investmoz-homologacao/releases",
|
||||
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
|
||||
},
|
||||
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
|
||||
},
|
||||
"fresh_backup": {
|
||||
"stage": "/var/backups/investmoz-ispc-l4-delivery-20261025/backup",
|
||||
"created_at": "2026-10-25T15:25:16Z",
|
||||
"target": {
|
||||
"database": "teste_investidor",
|
||||
"port": 5432
|
||||
},
|
||||
"tables": 174,
|
||||
"files_verified": 369,
|
||||
"dump_sha256": "77ba24736ff574d9273845359db90d1a032ff0f39d7f9195efaeff842d5b5857",
|
||||
"files_sha256": "59917d3f0420dc8ede0562da70ae5f67877aa99f77313950f9e1d840b7505e3b",
|
||||
"restore_verified": false
|
||||
},
|
||||
"isolated_restore": {
|
||||
"restore_verified": true,
|
||||
"tables_verified": 174,
|
||||
"container_network": "none",
|
||||
"database": "ispc_l4_restore_20261025",
|
||||
"port": 55441,
|
||||
"source_dump_sha256": "77ba24736ff574d9273845359db90d1a032ff0f39d7f9195efaeff842d5b5857",
|
||||
"active_database_writes": 0
|
||||
},
|
||||
"installed_protected_delta": {
|
||||
"installed": {
|
||||
"status": "installed",
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"release": "/var/www/investmoz-homologacao/releases/6af7092e83b9b3932712aa7a9f527393fcec4da8-647c8e2e",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0
|
||||
},
|
||||
"runtime_files_verified": 9,
|
||||
"L3_unchanged_runtime_files_verified": 11,
|
||||
"documentary_files_verified": 17,
|
||||
"persistent_files_and_env_verified": 369,
|
||||
"tables_compared": 174,
|
||||
"changed_tables": {
|
||||
"cache": {
|
||||
"before": {
|
||||
"rows": 106,
|
||||
"checksum": "81ca74112a72e3638ad335678ebfd0ef"
|
||||
},
|
||||
"after": {
|
||||
"rows": 106,
|
||||
"checksum": "e799b80b260c8c23326c72a5d7c52881"
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"before": {
|
||||
"rows": 156,
|
||||
"checksum": "5b29e80e2877c2e0bf0c81e046230987"
|
||||
},
|
||||
"after": {
|
||||
"rows": 157,
|
||||
"checksum": "e83a47d5ba184b55f1680f52ff7e0993"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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
|
||||
},
|
||||
"operational_delta": {
|
||||
"status": "operational_delta_reconciled",
|
||||
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
|
||||
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
|
||||
"sessions": "anonymous sessions created by exact delivery verification user-agent",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessions": {
|
||||
"before_rows": 156,
|
||||
"after_rows": 159,
|
||||
"changes": [
|
||||
{
|
||||
"key_sha256": "5045187d392f685b58ae0ce1749c84eb5a30c5ab441aa0e65cfc6d905d0180fa",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
},
|
||||
{
|
||||
"key_sha256": "3d45feddb6a0eafd7d40e3efe516866803e4432d922c6a6b6e839276d8461075",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
},
|
||||
{
|
||||
"key_sha256": "712b82ddcfb6f6af6a4ea5937ae2d5195976cf4c808e6202a4b234eef1560210",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"business_tables_to_confirm_separately": 172,
|
||||
"active_data_writes_by_comparison": 0,
|
||||
"restore_network": "none"
|
||||
},
|
||||
"installed_public": {
|
||||
"status": "installed_delta_verified",
|
||||
"served_revision": {
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"branch": "main",
|
||||
"built_at": "2026-10-25T15:29:39.962545+00:00",
|
||||
"manifest_sha256": "0761702f0aa0f54dd4e7dac14efadf290830c52a5762a97733d82f5332fb44a8"
|
||||
},
|
||||
"manifest_hash_matches": true,
|
||||
"compiled_delta_markers": {
|
||||
"ISPC — enquadramento e opção": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"ISPC — apuramento trimestral": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"ISPC — retenção em aquisições ocasionais": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar apuramento trimestral ISPC": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Conferir e guardar retenção ISPC": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Repartição do IVA documental em MZN": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Reconciliação da dedução anterior": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Cálculos indeterminados e condições para resolver": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Preparação dos quadros L3 e formalidades": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar restituição E": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar acompanhamento D": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar substituições C": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
]
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"file": "assets/project-dossier-document-DlW49dDv.js",
|
||||
"status": 200,
|
||||
"sha256": "7002e22485098102c9a49e6f637a8818a4ecb153cf58f9c9cfb377e1b8a3d5a0"
|
||||
},
|
||||
{
|
||||
"file": "assets/simulation-form-BqVD91Ek.js",
|
||||
"status": 200,
|
||||
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
|
||||
},
|
||||
{
|
||||
"file": "assets/project-dossier-B9kwzlsI.js",
|
||||
"status": 200,
|
||||
"sha256": "c2b62654e0a286c0dfb16a44f3aac513064c8db305cccc827388de35cc6c720f"
|
||||
},
|
||||
{
|
||||
"file": "assets/services-tj9wihZS.js",
|
||||
"status": 200,
|
||||
"sha256": "9e88d806f7c8e7193dda407ba1efe8bf720e5eeb76ca40798f3e6c4914e57f4b"
|
||||
}
|
||||
],
|
||||
"simulator_status": 200,
|
||||
"simulator_entry": "assets/app-CkfkH6Xv.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_status": {
|
||||
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
|
||||
"installed": {
|
||||
"status": "installed",
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"release": "/var/www/investmoz-homologacao/releases/6af7092e83b9b3932712aa7a9f527393fcec4da8-647c8e2e",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0
|
||||
},
|
||||
"latest_report": {
|
||||
"status": "installed",
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"release": "/var/www/investmoz-homologacao/releases/6af7092e83b9b3932712aa7a9f527393fcec4da8-647c8e2e",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0,
|
||||
"requested_commits": [
|
||||
"6af7092e83b9b3932712aa7a9f527393fcec4da8"
|
||||
],
|
||||
"finished_at": "2026-10-25T15:29:42.957691+00:00"
|
||||
},
|
||||
"log_file": "1792941995601985924.log",
|
||||
"summaries": [
|
||||
"OK (1 test, 3106 assertions)",
|
||||
"built in 31.63s",
|
||||
"OK (59 tests, 317 assertions)",
|
||||
"# tests 782",
|
||||
"# pass 782",
|
||||
"# fail 0"
|
||||
],
|
||||
"log_bytes": 227445
|
||||
},
|
||||
"archived_old_build_dependencies": {
|
||||
"status": "dependencies_archived_and_verified",
|
||||
"versions": 8,
|
||||
"free_before": 5531414528,
|
||||
"free_after": 7635984384,
|
||||
"receipt": "/var/backups/investmoz-build-dependencies-ispc-l4-20261025/receipt.json",
|
||||
"protected": [
|
||||
"/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"/var/www/investmoz-homologacao/releases/7ad187f9f0745245268e3ed5317547a96b4700f3-066618f1"
|
||||
],
|
||||
"active_or_previous_release_modified": false,
|
||||
"source_data_backups_deleted": 0
|
||||
},
|
||||
"accepted_QA_proofs_reused": {
|
||||
"prior_proofs": "L4-A12testes eL1/L2/L3/P001não repetidos;inventário eaceitações reutilizados",
|
||||
"new_frontend": "13distinctpassed:10quarter/3withholding;frontend-final.txt",
|
||||
"private_API": "1test/21assertions passed;loopback55441/simulator_fiscal_delta_20261021_test,DatabaseTransactions rollback;otheraccount404;api.txt",
|
||||
"UI": "Componentesreais:avaliar/opçãoguardada→calcular→guardarficheiroQA→recuperar→relatório;persistênciaprivadaconferidaemAPIseparadamente;ui-recovered-report.txt/png",
|
||||
"report_fix": "GrupoISPCmapeadoàsecçãofinanceira;testeactualdoexportadorincluiimposto/opção;ausênciaidentificadanademonstraçãoecorrigidaantesdeconcluir.",
|
||||
"types": "exit0;types-final.txt",
|
||||
"build": "exit0;build-final.txt",
|
||||
"inventory": "outputs/ispc-l4b-20261025/preservation-before-tests.json;reutiliza8143ficheirosinventariadoseL1fechados"
|
||||
},
|
||||
"manual_functional_tests_repeated": false,
|
||||
"pipeline_checks": "Existing Git process mandatory checks only;no new discretionary functional round.",
|
||||
"example": {
|
||||
"context": "opportunity:375;SYNTHETIC QA",
|
||||
"option": "documentada2026-01-01",
|
||||
"quarter": "2026/T2",
|
||||
"prior_turnover_MZN": "100000",
|
||||
"quarter_base_MZN": "200000",
|
||||
"rate_percent": 12,
|
||||
"tax_MZN": "24000",
|
||||
"payment_MZN": "24000",
|
||||
"declaration": "mantida",
|
||||
"other_fiscal_books": "exactamente preservados"
|
||||
},
|
||||
"remaining_L4_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
],
|
||||
"L3": "Preserved;11runtimehashes,17originals and additive integrations verified. Specific residuals remain in existing matrix.",
|
||||
"preserved_L3_amounts": {
|
||||
"documentary_VAT_MZN": 16,
|
||||
"deduction_this_route_MZN": 0,
|
||||
"recognised_MZN": 12,
|
||||
"received_MZN": 7,
|
||||
"awaiting_receipt_MZN": 5
|
||||
},
|
||||
"residuals": "P001/P058awaitdefinedclarificationswithoutblocking;P084/P085closed;statistics/AIdeferred.",
|
||||
"schema_migrations": 0,
|
||||
"content_imports": 0,
|
||||
"ISPC_integrally_completed": false,
|
||||
"proof_hashes": {
|
||||
"outputs/ispc-l4-delivery-20261025/preflight.txt": "985e4cabc9f4f80ee55f89aa9a20580c1bc3b691225241165b01cc66ba4b5d19",
|
||||
"outputs/ispc-l4-delivery-20261025/backup.txt": "23f72466038eed5153c93408e5acd508b5c6a66fc0e4c3a9bd30a580367fe8ea",
|
||||
"outputs/ispc-l4-delivery-20261025/restore.txt": "d0100e1378c2e0e8a4be61de640e0e331695721080bae16d8a7a708cf4d4eb83",
|
||||
"outputs/ispc-l4-delivery-20261025/integration.txt": "d92b419bd0c57c7951d558039e1414acca4ec2abc47e5a9d2f2389b1401adf7c",
|
||||
"outputs/ispc-l4-delivery-20261025/status-final.txt": "638710d6205b634b8ab8f8cf625ee308fb76c4fe7c21608130d2b79afba60e0c",
|
||||
"outputs/ispc-l4-delivery-20261025/installed-protected.txt": "83231f0b6619828618188e7abb9337f6b5e92e4192f7e5a8bbf165f7d2b70a44",
|
||||
"outputs/ispc-l4-delivery-20261025/installed-public-delta.json": "7b944512bd87b5fa99e83e554247f1567c5629481b2dcdf668b411f118849aa2",
|
||||
"outputs/ispc-l4-delivery-20261025/operational-delta.txt": "e79fc1267ac6f06e0f2fe78a9ed00eb0cfc05b1ec1ab7bec92c61268e4acbd93",
|
||||
"outputs/ispc-l4-delivery-20261025/compact-dependencies.txt": "236ebb16564acf706dd434186b20013b9c035dd201f5f728ebcaf1e3813e2053"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
{
|
||||
"status": "prepared_for_Git_delivery_not_installed",
|
||||
"authorization": "Tempo25/10:preparar entrega do âmbito L4 trimestral habitual demonstrado em6af7092e;conferir apenas delta,preservarL3;sem declararL4integralmenteconcluído.",
|
||||
"installed_baseline": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"candidate": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"branch": "codex/ispc-l4-quarterly-qa-20261025",
|
||||
"changes": [
|
||||
"docs/investmoz/simulations/integrated-review-continuation-20261020-receipt.json",
|
||||
"docs/investmoz/simulations/ispc-l4-quarterly-qa-20261025.json",
|
||||
"docs/investmoz/simulations/ispc-l4a-eligibility-qa-20261025.json",
|
||||
"docs/investmoz/simulations/l3-additional-delivery-20261025.json",
|
||||
"docs/investmoz/simulations/l3-e-additional-coverage-qa-20261025.json",
|
||||
"docs/investmoz/unification/traceability-and-manual.md",
|
||||
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
|
||||
"resources/js/components/simulation-form.tsx",
|
||||
"resources/js/components/simulation-ispc-eligibility.tsx",
|
||||
"resources/js/components/simulation-ispc-quarter.tsx",
|
||||
"resources/js/components/simulation-ispc-withholding.tsx",
|
||||
"resources/js/lib/ispc-eligibility.ts",
|
||||
"resources/js/lib/ispc-quarter.ts",
|
||||
"resources/js/lib/ispc-withholding.ts",
|
||||
"resources/js/lib/project-dossier-report.ts",
|
||||
"resources/js/lib/project-dossier.ts",
|
||||
"tests/Feature/IspcQuarterDraftTest.php",
|
||||
"tests/frontend/fixtures/ispc-quarter-preserved.json",
|
||||
"tests/frontend/ispc-eligibility.test.mjs",
|
||||
"tests/frontend/ispc-quarter.test.mjs",
|
||||
"tests/frontend/ispc-withholding.test.mjs"
|
||||
],
|
||||
"runtime_delta": [
|
||||
{
|
||||
"path": "resources/js/components/simulation-form.tsx",
|
||||
"sha256_LF": "606e6e29f92323450433e8411b2064ba5f55b795a3376794ad1eb30729841c3c"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
|
||||
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-quarter.tsx",
|
||||
"sha256_LF": "0b950091e9204b2b20823694ea16dc94e4863914080542253966367a5580d62d"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-withholding.tsx",
|
||||
"sha256_LF": "e688a8d6a2e1e20c1e10a85d33152d58a5c14867672cf4ffb834980ec1732f08"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/ispc-eligibility.ts",
|
||||
"sha256_LF": "d8c3ab8b2687af905d3048db192b690fa6d49ab693ff58f2e8f57f76dfb4a1fb"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/ispc-quarter.ts",
|
||||
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/ispc-withholding.ts",
|
||||
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/project-dossier.ts",
|
||||
"sha256_LF": "a24e0484f558580c14c4a261de66db8d245ffccf9c6fe17b6d639e9e2cbbe3c2"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/project-dossier-report.ts",
|
||||
"sha256_LF": "0db9f5fcb2929fd8340894bd13b74ee7c400af25e483ddfe5651002fd7160f49"
|
||||
}
|
||||
],
|
||||
"existing_integrations_additions_only": {
|
||||
"resources/js/components/simulation-form.tsx": 6,
|
||||
"resources/js/lib/project-dossier.ts": 6,
|
||||
"resources/js/lib/project-dossier-report.ts": 1
|
||||
},
|
||||
"L3_runtime_preserved_unchanged": [
|
||||
"resources/js/components/acquisition-beverage-restitution.tsx",
|
||||
"resources/js/components/fiscal-calculation-gaps.tsx",
|
||||
"resources/js/components/fiscal-l3-preparation.tsx",
|
||||
"resources/js/components/simulation-acquisitions.tsx",
|
||||
"resources/js/components/simulation-operations.tsx",
|
||||
"resources/js/lib/iva-acquisition-bc.ts",
|
||||
"resources/js/lib/iva-beverage-allocation.ts",
|
||||
"resources/js/lib/iva-beverage-restitution.ts",
|
||||
"resources/js/lib/iva-calculation-gaps.ts",
|
||||
"resources/js/lib/iva-operations.ts",
|
||||
"resources/js/lib/l3-form-preparation.ts"
|
||||
],
|
||||
"L3_documentary_originals_preserved": 17,
|
||||
"documentary_delta": [
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
|
||||
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
|
||||
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
|
||||
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
|
||||
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
|
||||
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
|
||||
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
|
||||
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
|
||||
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
|
||||
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
|
||||
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
|
||||
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
|
||||
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
|
||||
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
|
||||
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
|
||||
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
|
||||
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
|
||||
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
|
||||
}
|
||||
],
|
||||
"schema_runtime_PHP_configuration_dependencies_delta": false,
|
||||
"P001_experimental_changes_excluded": true,
|
||||
"accepted_QA_proofs_reused": {
|
||||
"prior_proofs": "L4-A12testes eL1/L2/L3/P001não repetidos;inventário eaceitações reutilizados",
|
||||
"new_frontend": "13distinctpassed:10quarter/3withholding;frontend-final.txt",
|
||||
"private_API": "1test/21assertions passed;loopback55441/simulator_fiscal_delta_20261021_test,DatabaseTransactions rollback;otheraccount404;api.txt",
|
||||
"UI": "Componentesreais:avaliar/opçãoguardada→calcular→guardarficheiroQA→recuperar→relatório;persistênciaprivadaconferidaemAPIseparadamente;ui-recovered-report.txt/png",
|
||||
"report_fix": "GrupoISPCmapeadoàsecçãofinanceira;testeactualdoexportadorincluiimposto/opção;ausênciaidentificadanademonstraçãoecorrigidaantesdeconcluir.",
|
||||
"types": "exit0;types-final.txt",
|
||||
"build": "exit0;build-final.txt",
|
||||
"inventory": "outputs/ispc-l4b-20261025/preservation-before-tests.json;reutiliza8143ficheirosinventariadoseL1fechados"
|
||||
},
|
||||
"accepted_proof_hashes_verified": {
|
||||
"outputs/ispc-l4b-20261025/frontend-final.txt": "2b0ec25bb83505ec9ce8ace02e0860faeeac4ce233083859f9a502069944f49f",
|
||||
"outputs/ispc-l4b-20261025/api.txt": "2a770d07561a1475973795d5bac01ce5d94ee8a91be1d57d9b0702c621b8284d",
|
||||
"outputs/ispc-l4b-20261025/ui-recovered-report.txt": "234bae0f17ef84dd9928197bfa38ad4a8a05c2dae18051e1ea9bd88852bb84fa",
|
||||
"outputs/ispc-l4b-20261025/build-final.txt": "9683e783fd6e457c89a747d4a1a6deb10ba00a034f7891cf69e4c1a0cb1f0073",
|
||||
"outputs/ispc-l4b-20261025/types-final.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
|
||||
"tests/frontend/fixtures/ispc-quarter-preserved.json": "30266584de9cacb0e4d771a9cc9c38838b62a3472583792e13effcd094247c39"
|
||||
},
|
||||
"compatible_build_and_types": "Already passed on identical runtime hashes;proofs reused,no rerun.",
|
||||
"compiled_markers": {
|
||||
"ISPC — enquadramento e opção": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"ISPC — apuramento trimestral": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"ISPC — retenção em aquisições ocasionais": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar apuramento trimestral ISPC": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Conferir e guardar retenção ISPC": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Repartição do IVA documental em MZN": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Reconciliação da dedução anterior": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Cálculos indeterminados e condições para resolver": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Preparação dos quadros L3 e formalidades": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar restituição E": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar acompanhamento D": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
],
|
||||
"Calcular e guardar substituições C": [
|
||||
"assets/services-tj9wihZS.js"
|
||||
]
|
||||
},
|
||||
"public_baseline_readonly": {
|
||||
"commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"branch": "main",
|
||||
"built_at": "2026-10-25T15:12:37.806036+00:00",
|
||||
"manifest_sha256": "cddac25dc66b3e555f2380cf3a9d4b2da6501cd03927c183c832a05b0ee5c993"
|
||||
},
|
||||
"examples": {
|
||||
"context": "opportunity:375;SYNTHETIC QA",
|
||||
"option": "documentada2026-01-01",
|
||||
"quarter": "2026/T2",
|
||||
"prior_turnover_MZN": "100000",
|
||||
"quarter_base_MZN": "200000",
|
||||
"rate_percent": 12,
|
||||
"tax_MZN": "24000",
|
||||
"payment_MZN": "24000",
|
||||
"declaration": "mantida",
|
||||
"other_fiscal_books": "exactamente preservados"
|
||||
},
|
||||
"remaining_L4_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
],
|
||||
"preserved_amounts_L3": {
|
||||
"documentary_VAT_MZN": 16,
|
||||
"deduction_this_route_MZN": 0,
|
||||
"recognised_MZN": 12,
|
||||
"received_MZN": 7,
|
||||
"awaiting_receipt_MZN": 5
|
||||
},
|
||||
"residuals": "P001/P058awaitdefinedclarificationswithoutblocking;P084/P085closed;L3residualsremaininexistingmatrix;statistics/AIdeferred.",
|
||||
"execution_remaining": [
|
||||
"Fresh authenticated destination/schema/data/configuration/permissions and disk comparison.",
|
||||
"Fresh backup and verified isolated restore,without modifying active database.",
|
||||
"Fast-forward integration via existing Git process only after guards pass;verify servedrevision,manifest,compiled L4/L3 markers and protected delta with equivalent identities/context."
|
||||
],
|
||||
"backup_restore": "Not executed in preparation;prior L3 receipt preserved,not represented as fresh L4 backup.",
|
||||
"main_changed": false,
|
||||
"active_changes": false,
|
||||
"Git_preparation": {
|
||||
"feature_ref": "refs/heads/codex/ispc-l4-quarterly-qa-20261025",
|
||||
"remote_verified": {
|
||||
"refs/heads/codex/ispc-l4-quarterly-qa-20261025": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"refs/heads/main": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6"
|
||||
},
|
||||
"bundle": "outputs/ispc-l4-delivery-20261025/candidate.bundle",
|
||||
"bundle_sha256": "2d1b690ffbca0cdcc2365d2f5c8cf9f4d34a3e64f9cb5bd4fa2ce23835143c4d",
|
||||
"bundle_verified": true,
|
||||
"main_pushed": false
|
||||
},
|
||||
"execution_scripts": {
|
||||
"outputs/ispc-l4-delivery-20261025/backup.py": "f82ee71b83527e2e3b431f88aa24deb0433308f4c15a2873779068a21785c99d",
|
||||
"outputs/ispc-l4-delivery-20261025/bridge.py": "b12bb51e68c0c3270ac9d127d20aaf69c04745837fb06788e9e1d37a623e3487",
|
||||
"outputs/ispc-l4-delivery-20261025/installer-status.py": "47cf71d02bbbac76bdf8edf87ab9b69b88d6c610d4b1755e1da69060af8b02cf",
|
||||
"outputs/ispc-l4-delivery-20261025/integrate-after-guards.py": "b2146ae221af4fa5f26f3a16ba7de22eb3d35fed2ff9b606f49065b0a9524171",
|
||||
"outputs/ispc-l4-delivery-20261025/preflight.py": "d22ae1370f261cce91201830f39833d03019df5110be8aa5a9eccdfd639de55c",
|
||||
"outputs/ispc-l4-delivery-20261025/reconcile-operational-delta.py": "d2e2ab7093594ab667b03f76ef7620120d7fd580e22edeb335b3c5c208493cd0",
|
||||
"outputs/ispc-l4-delivery-20261025/restore.py": "51c03e0e590f3ad8d795334e67140f6de7c594fe52fb5ee9098b2da8bc508a3b",
|
||||
"outputs/ispc-l4-delivery-20261025/verify-protected.py": "5acdb275e6bd5de5237000f8a8a27234f9d00be4bf1cd1cf71ecf24bc0a7f415",
|
||||
"outputs/ispc-l4-delivery-20261025/verify-public.py": "e31052548421a2095d23435a716c34086542992fda3ede04f6ae3cd1d24f291b"
|
||||
},
|
||||
"execution_script_checks": "Python syntax checked;not executed against active target. Authenticated baseline,fresh backup/isolatedrestore andtimestamp guards prepared;disk comparison pending at execution.",
|
||||
"guard_origins": {
|
||||
"base_and_scope": "DecisãoTempo:preservarL3fa32 eentregar apenas âmbitoQA6af.",
|
||||
"disk_5_GiB": "Requisito técnico do processo de entrega já existente;conferido no código emexecuçãoL3,sem criar regra organizacional.",
|
||||
"backup_freshness_30_minutes": "Escolha técnica do script de integração;expiração exige actualizar preflight/backup-restauro,sem nova aprovação organizacional."
|
||||
},
|
||||
"superseded_by": "ispc-l4-delivery-20261025.json",
|
||||
"installation_followup": "6af7092e83b9b3932712aa7a9f527393fcec4da8"
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"status": "installed_scoped_habitual_quarterly_ISPC",
|
||||
"matrix_anchor": "AUD-SIM-INT02",
|
||||
"scope": "Actividade habitual ISPC2026/MZN, enquadramento/opção, cálculo trimestral e retenção12(3–4) delimitada. Não é encerramento de operações ocasionais próprias ou formalidades sem correspondência de modelo.",
|
||||
"source": {
|
||||
"file": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
|
||||
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
|
||||
"citation": "Lei9/2025,republicaçãoISPC,arts8–12;PDF11/p2180(11),enquadramento2–5PDF10",
|
||||
"application": "8(1)a selecciona taxa3/4/5 pelo volume anual2026 declarado e9 aplica-a à base trimestral; não repartir limites anuais por4 nem copiar acesso2025. Serviços12/15; cumulação usa taxa maior8(2).20%somenteparcela acima limite anual4.000.000 com acumulado anterior; cálculos racionais exactos."
|
||||
},
|
||||
"new_implementation": [
|
||||
"Livro trimestral por contexto; receitas de cada trimestre e suporte explícitos,volume global do sujeito passivo confirmado; previsão anual distinta de ano encerrado reconciliado.",
|
||||
"Elegibilidade actual e opção documentada reutilizadas; preparação apenas simula; opção posterior ao trimestre não retroage automaticamente.",
|
||||
"Imposto/prestação/obrigação declarativa separados; inferior500 dispensa pagamento, não declaração;igual500 mantém pagamento. Não acumular dispensas nem deduzir custos/IVA.",
|
||||
"Retenção5%separada para aquisições ocasionais a pessoa singular não inscrita3(3–4),ligadasàactividade,limiteglobalanual2.500.000;acima limiteindeterminado,semtruncar. Sem crédito contraimpostopróprio,mínimo500não aplicadoàretenção.",
|
||||
"Gravação/recuperação mantém outros livros e históricos;alterações conservam resultado congelado até nova versão;relatório financeiro inclui grupoISPC."
|
||||
],
|
||||
"verification": {
|
||||
"prior_proofs": "L4-A12testes eL1/L2/L3/P001não repetidos;inventário eaceitações reutilizados",
|
||||
"new_frontend": "13distinctpassed:10quarter/3withholding;frontend-final.txt",
|
||||
"private_API": "1test/21assertions passed;loopback55441/simulator_fiscal_delta_20261021_test,DatabaseTransactions rollback;otheraccount404;api.txt",
|
||||
"UI": "Componentesreais:avaliar/opçãoguardada→calcular→guardarficheiroQA→recuperar→relatório;persistênciaprivadaconferidaemAPIseparadamente;ui-recovered-report.txt/png",
|
||||
"report_fix": "GrupoISPCmapeadoàsecçãofinanceira;testeactualdoexportadorincluiimposto/opção;ausênciaidentificadanademonstraçãoecorrigidaantesdeconcluir.",
|
||||
"types": "exit0;types-final.txt",
|
||||
"build": "exit0;build-final.txt",
|
||||
"inventory": "outputs/ispc-l4b-20261025/preservation-before-tests.json;reutiliza8143ficheirosinventariadoseL1fechados"
|
||||
},
|
||||
"example": {
|
||||
"context": "opportunity:375;SYNTHETIC QA",
|
||||
"option": "documentada2026-01-01",
|
||||
"quarter": "2026/T2",
|
||||
"prior_turnover_MZN": "100000",
|
||||
"quarter_base_MZN": "200000",
|
||||
"rate_percent": 12,
|
||||
"tax_MZN": "24000",
|
||||
"payment_MZN": "24000",
|
||||
"declaration": "mantida",
|
||||
"other_fiscal_books": "exactamente preservados"
|
||||
},
|
||||
"remaining_specific": [
|
||||
"Operações ocasionais próprias3(3–4)enquanto sujeito passivo,distintas da retenção do adquirente;mantidas indeterminadas no percurso específico.",
|
||||
"Aquisições acima limiteglobal2.500.000:correspondência do tratamento próprio;nãoliquidar5%porpresunção.",
|
||||
"Formulário/modelo,instruções eprocedimentos da regulamentação2026;relatório depreparação não édeclaraçãosubmetida. Aviso primário do Governo confirma aprovação de novo regulamento,mas não contém articulado/modelos: https://portaldogoverno.gov.mz/governo-introduz-alteracoes-nos-regulamentos-fiscais-para-reforcar-eficiencia-tributaria/ . Sem impor segunda validação jurídica ou repetir pesquisa sem nova evidência."
|
||||
],
|
||||
"active_changes": false,
|
||||
"schema_changes": false,
|
||||
"rules_published_or_activated": 0,
|
||||
"residuals": "P001/P058nãointerrompem;P084/P085fechados;L3residuaisapenasbloqueiamcasosdependentes;estatísticas/IAadiadas.",
|
||||
"runtime_hashes": {
|
||||
"resources/js/lib/ispc-quarter.ts": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129",
|
||||
"resources/js/lib/ispc-withholding.ts": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4",
|
||||
"resources/js/components/simulation-ispc-quarter.tsx": "0b950091e9204b2b20823694ea16dc94e4863914080542253966367a5580d62d",
|
||||
"resources/js/components/simulation-ispc-withholding.tsx": "e688a8d6a2e1e20c1e10a85d33152d58a5c14867672cf4ffb834980ec1732f08",
|
||||
"resources/js/lib/project-dossier-report.ts": "0db9f5fcb2929fd8340894bd13b74ee7c400af25e483ddfe5651002fd7160f49"
|
||||
},
|
||||
"proof_hashes": {
|
||||
"outputs/ispc-l4b-20261025/frontend-final.txt": "2b0ec25bb83505ec9ce8ace02e0860faeeac4ce233083859f9a502069944f49f",
|
||||
"outputs/ispc-l4b-20261025/api.txt": "2a770d07561a1475973795d5bac01ce5d94ee8a91be1d57d9b0702c621b8284d",
|
||||
"outputs/ispc-l4b-20261025/ui-recovered-report.txt": "234bae0f17ef84dd9928197bfa38ad4a8a05c2dae18051e1ea9bd88852bb84fa",
|
||||
"outputs/ispc-l4b-20261025/build-final.txt": "9683e783fd6e457c89a747d4a1a6deb10ba00a034f7891cf69e4c1a0cb1f0073",
|
||||
"outputs/ispc-l4b-20261025/types-final.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
|
||||
"tests/frontend/fixtures/ispc-quarter-preserved.json": "30266584de9cacb0e4d771a9cc9c38838b62a3472583792e13effcd094247c39"
|
||||
},
|
||||
"compatible_QA_preparation": {
|
||||
"branch": "codex/ispc-l4-quarterly-qa-20261025",
|
||||
"path": "C:\\laragon\\www\\portal-investidor-ispc-qa-20261025",
|
||||
"base": "fa32a2b9",
|
||||
"runtime_files": [
|
||||
"resources/js/components/simulation-form.tsx",
|
||||
"resources/js/components/simulation-ispc-eligibility.tsx",
|
||||
"resources/js/components/simulation-ispc-quarter.tsx",
|
||||
"resources/js/components/simulation-ispc-withholding.tsx",
|
||||
"resources/js/lib/ispc-eligibility.ts",
|
||||
"resources/js/lib/ispc-quarter.ts",
|
||||
"resources/js/lib/ispc-withholding.ts",
|
||||
"resources/js/lib/project-dossier.ts",
|
||||
"resources/js/lib/project-dossier-report.ts"
|
||||
],
|
||||
"runtime_hashes_match_accepted_QA": true,
|
||||
"P001_runtime": "fa32a2b9 unchanged; experimental d1551dab runtime excluded",
|
||||
"compatible_build": "exit0;outputs/ispc-l4b-20261025/compatible-build.txt",
|
||||
"compatible_types": "exit0;outputs/ispc-l4b-20261025/compatible-types.txt",
|
||||
"functional_proofs": "13frontend/API1-21/UIreport reused; no new functional round",
|
||||
"installed": true,
|
||||
"functional_source_commits": [
|
||||
"479b6681",
|
||||
"1b7ccfee"
|
||||
],
|
||||
"candidate_commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"functional_candidate_commit": "49b448eb47df9ded3f906996e36c1d5ebd855741",
|
||||
"installed_at_preparation": false,
|
||||
"installed_commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8"
|
||||
},
|
||||
"QA_status_before_delivery": "QA_demonstrated_eligibility_option_quarter_calculation_private_recovery_and_report_not_installed",
|
||||
"installation_followup_20261025": {
|
||||
"status": "installed_scoped_habitual_quarterly",
|
||||
"commit": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"receipt": "ispc-l4-delivery-20261025.json",
|
||||
"QA_proofs": "preserved;no manual repetition",
|
||||
"ISPC_integrally_completed": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"status": "QA_partial_eligibility_and_separate_option_not_installed",
|
||||
"matrix_anchor": "AUD-SIM-INT02",
|
||||
"authorization": "Tempo25/10: preparar entrega compatível L3, reconciliar saldo e avançar L4 ISPC; P001 residual não bloqueia trabalho independente.",
|
||||
"source": {
|
||||
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
|
||||
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
|
||||
"law": "Lei9/2025, republicação ISPC; arts2–5,9-A/13; PDF10–11; vigência2026art6/PDF9",
|
||||
"acceptance": "Fonte oficial aceite pela Tempo; sem segunda validação de proveniência ou aprovação genérica Fiscalista."
|
||||
},
|
||||
"scope": [
|
||||
"Condições preliminares de acesso habitual em2026/MZN; pessoa,actividade nacional,volume anterior2025 ou previsão de início2026,contabilidade obrigatória e exclusões3(2).",
|
||||
"Limite4.000.000 inclusivo; desconhecido permanece indeterminado e não vira zero; operação ocasional tem percurso próprio ainda não implementado.",
|
||||
"Serviços liberais8(1)c:183dias versus184 à mesma entidade; não aplicar esta exclusão aos serviços8(1)b.",
|
||||
"Opção separada de elegibilidade; seleccionarISPC não adopta regime nem alteraIVA/IRPS/IRPC.",
|
||||
"Reutilização de perfil com diferenças e confirmação; nenhuma inferência de categoria,volume anual anterior ou opção a partir de vendas correntes.",
|
||||
"Livro por contexto no snapshot existente; preserva mapas fiscais,histórico e resultados congelados; relatório do dossier inclui enquadramento e opção."
|
||||
],
|
||||
"verification": {
|
||||
"inventory_before_tests": "outputs/ispc-l4a-20261025/preservation-before-tests.json",
|
||||
"new_frontend_tests": 12,
|
||||
"frontend_result": "12 passed/0failed; outputs/ispc-l4a-20261025/frontend.txt",
|
||||
"types": "exit0;outputs/ispc-l4a-20261025/types.txt",
|
||||
"build": "exit0;outputs/ispc-l4a-20261025/build.txt",
|
||||
"persistence": "serialização/recuperação e preservação dos livros/históricos cobertas nos novos testes; transporte privado existente reutilizado,sem nova rondaAPI",
|
||||
"UI": "componente integrado;sem demonstração visual nova nesta passagem",
|
||||
"synthetic_fixture": "outputs/ispc-l4a-20261025/calculated.json; não importada no activo"
|
||||
},
|
||||
"remaining_L4": [
|
||||
"Apuramento trimestral e aplicação dos escalões3/4/5%,serviços12%,liberal15%,excesso20% e actividades mistas8; identificar correspondência exacta anual/trimestral antes do cálculo.",
|
||||
"Mínimo trimestral500 e obrigação declarativa; retenção5% nas aquisições ocasionais próprias,limite2.500.000 e modelo; sem reutilizar taxa deIVA.",
|
||||
"Percurso ocasional3(3–4),formalidades,modelos e prazos do regulamento aplicável; conferir apenas correspondências concretas necessárias,sem nova validação genérica.",
|
||||
"Demonstração visual integrada e gravação privada deste incremento antes de propor entregaL4."
|
||||
],
|
||||
"preserved": {
|
||||
"L1": "131entregues;P001residual;P058parcial com exclusões",
|
||||
"P084_P085": "fechados no âmbito operacional Tempo;sem pesquisa",
|
||||
"L3": "candidata0f4df8a4 preparada,não instalada;saldo próprio não encerraL3",
|
||||
"E_original": "16MZN documental/zero dedução nesta via/12 reconhecidos/7recebidos/5porreceber",
|
||||
"statistics_AI": "adiadas"
|
||||
},
|
||||
"active_changes": false,
|
||||
"schema_changes": false,
|
||||
"runtime_hashes": {
|
||||
"resources/js/lib/ispc-eligibility.ts": "1828cb2d696a6bd852078fc3f1cf90a6649c1f3a0df5bec0a72ac1d1f175b2eb",
|
||||
"resources/js/components/simulation-ispc-eligibility.tsx": "38ebe2b2fd340e269ba6fdeec96f0d39d0594892b9cb968ec094b2c165346b42",
|
||||
"resources/js/components/simulation-form.tsx": "5090175a3fee965795fb47ac7f673c5aafc3641c25d323be0be631178afae775",
|
||||
"resources/js/lib/project-dossier.ts": "de70672560162ef94f1e5429f70c2466a8347e73b2d800da013c7c50e480091c"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
{
|
||||
"status": "QA_grouped_compatible_delta_not_installed",
|
||||
"matrix_anchor": "AUD-SIM-INT02",
|
||||
"base_installed": "6af7092e83b9b3932712aa7a9f527393fcec4da8",
|
||||
"branch": "codex/ispc-residuals-qa-20261025",
|
||||
"scope": "Operações ocasionais próprias3(3–4),aquisições acima do limite12(3)comcorrespondênciapositivaIRPS57(2k),preparação/transporte de camposB–Geral e histórico externo;semfechointegralISPC.",
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
|
||||
"bytes": 308401,
|
||||
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973",
|
||||
"availability": "private source archive;not automatically published/imported into active library",
|
||||
"scan": "not claimed"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
|
||||
"bytes": 319577,
|
||||
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57",
|
||||
"availability": "private source archive;not automatically published/imported into active library",
|
||||
"scan": "not claimed"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
|
||||
"bytes": 159748,
|
||||
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c",
|
||||
"availability": "private source archive;not automatically published/imported into active library",
|
||||
"scan": "not claimed"
|
||||
},
|
||||
{
|
||||
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
|
||||
"bytes": 1894997,
|
||||
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d",
|
||||
"availability": "private source archive;not automatically published/imported into active library",
|
||||
"scan": "not claimed"
|
||||
}
|
||||
],
|
||||
"official_source_inventory": {
|
||||
"local_reused": "outputs/ispc-l4a-20261025/preservation-before-tests.json",
|
||||
"AT_forms": "39documents;at-forms.json",
|
||||
"AT_legislation": "189documents;at-legislation.json",
|
||||
"AT_communications": "4documents;at-communications.xml",
|
||||
"provenance": "AT public document APIs reached through links/configuration of the official website;BR2017 republication hostedOCAM;no generic second authenticity validation",
|
||||
"AT_comunicado": {
|
||||
"url": "https://www.at.gov.mz/api/webdav?path=%2FINFORMA%C3%87%C3%95ES%2FCOMUNICADO%20DE%20IMPRENSA%2F07-10-2026%20-%20COMUNICADO%20N%C2%BA9_2026%20-%20CUMPRIMENTO%20DAS%20OBRIGA%C3%87%C3%95ES%20DECLARATIVAS%20E%20DE%20PAGAMENTO%20DO%20ISPC.pdf",
|
||||
"listing": "https://www.at.gov.mz/informacoes/comunicado-de-imprensa",
|
||||
"file": "C:\\laragon\\www\\portal-investidor-ispc-residuals-qa-20261025\\docs\\investmoz\\simulations\\source-archive\\AT-Comunicado-9-2026-ISPC.pdf",
|
||||
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973",
|
||||
"bytes": 308401,
|
||||
"origin": "AT official website; public document linked from communications page",
|
||||
"automatic_rule_activation": false
|
||||
},
|
||||
"AT_forms_selected": [
|
||||
{
|
||||
"id": "ed263a2ecdd81846af4cdc8f75fc76c1",
|
||||
"title": "Modelo 30 ISPC IMPOSTO SIMPLIFICADO PARA PEQUENOS CONTRIBUINTES",
|
||||
"description": "Documentação oficial sincronizada em tempo real.",
|
||||
"size": "156 KB",
|
||||
"date": "06/01/2026",
|
||||
"url": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIRPC%2FModelo%2030%20ISPC%20IMPOSTO%20SIMPLIFICADO%20PARA%20PEQUENOS%20CONTRIBUINTES.pdf",
|
||||
"downloadUrl": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIRPC%2FModelo%2030%20ISPC%20IMPOSTO%20SIMPLIFICADO%20PARA%20PEQUENOS%20CONTRIBUINTES.pdf",
|
||||
"viewUrl": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIRPC%2FModelo%2030%20ISPC%20IMPOSTO%20SIMPLIFICADO%20PARA%20PEQUENOS%20CONTRIBUINTES.pdf",
|
||||
"file": "C:\\laragon\\www\\portal-investidor-ispc-residuals-qa-20261025\\docs\\investmoz\\simulations\\source-archive\\AT-Modelo-30-ISPC.pdf",
|
||||
"origin": "AT official forms directory",
|
||||
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c",
|
||||
"bytes": 159748
|
||||
},
|
||||
{
|
||||
"id": "c37f0377df612928865f37cfbfc9dabd",
|
||||
"title": "MODELO B GERAL",
|
||||
"description": "Documentação oficial sincronizada em tempo real.",
|
||||
"size": "312 KB",
|
||||
"date": "28/10/2025",
|
||||
"url": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIVA%2FMODELO%20B%20GERAL.pdf",
|
||||
"downloadUrl": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIVA%2FMODELO%20B%20GERAL.pdf",
|
||||
"viewUrl": "/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIVA%2FMODELO%20B%20GERAL.pdf",
|
||||
"file": "C:\\laragon\\www\\portal-investidor-ispc-residuals-qa-20261025\\docs\\investmoz\\simulations\\source-archive\\AT-Modelo-B-Geral.pdf",
|
||||
"origin": "AT official forms directory",
|
||||
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57",
|
||||
"bytes": 319577
|
||||
}
|
||||
],
|
||||
"IRPS_Bulletin_URL": "https://ocam.org.mz/wp-content/uploads/2024/06/Lei-n-19_2017-de-28-de-Dezembro-IRPS-2-1.pdf"
|
||||
},
|
||||
"implemented_calculations": [
|
||||
{
|
||||
"case": "Operação ocasional própria",
|
||||
"positive": "Pessoa singular,semactividadehabitual,actoimprevisível/nãoreiterado,nacional,nasfamílias3(4);IRPS8(3h,4)/9da republicação19/2017;ISPC4/5/8/9/10-A. Cenário100000MZN/3%=3000;opção/factosefectivosdistintosdeprevisão.",
|
||||
"anti_duplication": "Retenção liberatória5%documentadareconciliadacomabase não gera segunda liquidação própria;divergência ficaindeterminada,nãohácréditopresumido."
|
||||
},
|
||||
{
|
||||
"case": "Aquisição que atravessa2.500.000MZN",
|
||||
"positive": "Acumulado2400000+aquisição200000:parcela100000atélimite/retencão5000;excedente100000separado. SóactoIRPSqualificado57(2k),semopçãoISPCaplicável,comrendimentoilíquidoidentificado permite20000noexcedente;total25000de retenções,não imposto próprio do adquirente.",
|
||||
"limits": "Sem enquadramento/base/documentos,parcela excedente e total permanecem indeterminados. Fornecedor com opçãoISPC não recebeIRPS20automaticamente;factura/liquidação própria são âmbito separado. Não se usa20%do excesso de vendasISPC para compras."
|
||||
}
|
||||
],
|
||||
"implemented_formal_preparation": [
|
||||
"ATcomunicado9/2026visualizado:ModeloB–Geraltransitório,enquanto sistemaéajustado;mesesJaneiro/Abril/Julho/Outubro;nenhumdiadomêsinventado.",
|
||||
"OriginalB–Geral2pconferido:quadros1/2/3/5/6/8/10;linha1base01/montante05,linha2base02/montante06,subtotal09;numeração própria doquadro10nãosemisturacomquadro8.",
|
||||
"HTMLdepreparação,relatóriorecuperado efontes/originaispreservados;semrecriarformuláriooficial,assinatura,recibosouacçãodafuncionário. RetençõesISPC5/IRPS20descritas separadamente.",
|
||||
"Modelo30oficialdisponívelaindaexibe75.000/3%antigos:preservadoparaconsulta,nãotransportadopara2026.",
|
||||
"Estadosdepreparação/submissão/recepção/pagamentodeclaradoscomreferência/dataehistórico;sem efectuaressasacçõesoucertificarAT."
|
||||
],
|
||||
"remaining_calculations": [
|
||||
{
|
||||
"item": "Juros compensatórios",
|
||||
"state": "montante documentado pode ser conservado;fórmula ainda não implementada",
|
||||
"needed": "regra/taxa/base/período/dias efectivamente aplicáveis,no documento/instrução correspondente;sem zero ou taxa presumidos"
|
||||
},
|
||||
{
|
||||
"item": "Outros enquadramentos da parcela excedente",
|
||||
"state": "sem fórmula genérica;casos diferentes do acto isolado qualificado não recebem taxa automática",
|
||||
"needed": "natureza,regime do fornecedor,opção aplicável,base e suporte concretos;encaminhar para o cálculo próprio quando for outro regime,não bloquear o caso positivo implementado"
|
||||
}
|
||||
],
|
||||
"external_formal_dependencies": [
|
||||
{
|
||||
"item": "Quadro2doB–Geral",
|
||||
"needed": "correspondência concreta do mês/ano a inscrever para o trimestre;comunicado fornece meses de pagamento,que não são copiados automaticamente para período"
|
||||
},
|
||||
{
|
||||
"item": "Dispensa inferior500MZN noB–Geral",
|
||||
"needed": "Representação declarativa do imposto apurado com prestação dispensada10-A;sem preencher montanteapurado comozero porpresunção. O cálculo imposto/prestação jáestá implementado."
|
||||
},
|
||||
{
|
||||
"item": "Entrega de retenções",
|
||||
"needed": "modelo/código/instrução próprios12(3)ISPCe57(2k)IRPS;B–Geraldeapoio nãoéapresentadocomocorrespondênciacompletadestasretenções"
|
||||
},
|
||||
{
|
||||
"item": "Regulamentação2026/instruções de envio de facturas",
|
||||
"needed": "texto/exemplar/instrução concreta quando disponibilizado;comunicado transitório já implementado,não se mantém pesquisa genérica como aprovação adicional"
|
||||
},
|
||||
{
|
||||
"item": "Submissão e pagamento",
|
||||
"needed": "actos externos e comprovativos reais;nenhuma operaçãoATfoiexecutadaemQA"
|
||||
}
|
||||
],
|
||||
"operation_data_missing_in_synthetic_preparation": "Identidade/NUIT/área fiscal/domicílio,referência de período ejuros são dados para formalizar a operação,não nova condição de acesso ao cálculo.",
|
||||
"verification": {
|
||||
"preservation_before_tests": "outputs/ispc-residuals-20261025/preservation-before-tests.json",
|
||||
"new_frontend_distinct": 19,
|
||||
"frontend_proofs": [
|
||||
"frontend-final.txt:14passed",
|
||||
"directed-final.txt:1additionalpass",
|
||||
"directed-retention-form.txt:1additionalpass",
|
||||
"directed-known-exclusions.txt:1additionalpass",
|
||||
"directed-dispensation-form.txt:1additionalpass",
|
||||
"directed-liberatory-history.txt:1additionalpass"
|
||||
],
|
||||
"API": "1test/22assertionspassed;QAloopback55441/simulator_fiscal_delta_20261021_test;DatabaseTransactionsrollback;APP_BASE_PATHcandidateexplicit",
|
||||
"UI": "Vendedor376/adquirente375separados;3000/5000/20000/25000;guardar→recuperar→relatório;B–Geralpreparadodescarregado;visibilidadeapenasdascondiçõesafectadasverificada",
|
||||
"UI_proofs": [
|
||||
"ui-own-report.txt",
|
||||
"ui-acquisition-report.txt",
|
||||
"ui-occasional-applicability.txt",
|
||||
"ui-regular-applicability.txt",
|
||||
"preparation.html"
|
||||
],
|
||||
"types": "exit0;types-final.txt",
|
||||
"build": "exit0;build-final.txt",
|
||||
"habitual_re_evaluation": "not repeated;arithmetic engines unchanged;24000snapshotpreservedexactly;onlyconditionalvisibilitydeltaexamined"
|
||||
},
|
||||
"runtime_delta": [
|
||||
{
|
||||
"path": "resources/js/lib/ispc-residuals.ts",
|
||||
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-residuals.tsx",
|
||||
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-form.tsx",
|
||||
"sha256_LF": "07f7d0d73993ffc2924f1b9b2d21cbc53fb7c95aab959c0820fd7dbc35a1fffa"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/project-dossier.ts",
|
||||
"sha256_LF": "beca4eebd3959afa520061f231de25d064723537bd98deb541712ab448eba369"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/lib/ispc-eligibility.ts",
|
||||
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-quarter.tsx",
|
||||
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/simulation-ispc-withholding.tsx",
|
||||
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
|
||||
}
|
||||
],
|
||||
"compiled_markers": {
|
||||
"Calcular e guardar operações ocasionais": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Calcular e guardar parcela excedente": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Preparar e guardar campos B–Geral": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Descarregar preparação B–Geral": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Calcular e guardar apuramento trimestral ISPC": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Calcular e guardar restituição E": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Calcular e guardar acompanhamento D": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
],
|
||||
"Calcular e guardar substituições C": [
|
||||
"assets/services-Cvwv29Mo.js"
|
||||
]
|
||||
},
|
||||
"schema_backend_configuration_dependency_changes": false,
|
||||
"active_changes": false,
|
||||
"originals_previous_preserved": 17,
|
||||
"existing_books_preserved": "L3,ISPC habitual andacceptedhistories;no reset or overwrite of deliberateedits",
|
||||
"P001_P058": "unchanged;notblocking",
|
||||
"P084_P085": "closed",
|
||||
"statistics_AI": "deferred",
|
||||
"proof_hashes": {
|
||||
"outputs/ispc-residuals-20261025/frontend-final.txt": "bb0db1bde933e5fe08356537df1ba783003629f7fcc21abdcf18e119bcb0ab8d",
|
||||
"outputs/ispc-residuals-20261025/directed-final.txt": "9a2de706bca568599efd9dbfff7cb2c55ba037d64139e0b7d269271b9d84582b",
|
||||
"outputs/ispc-residuals-20261025/directed-retention-form.txt": "44061cb0f2661fb27b6c1e0acca437710d6569f482c0ad521bec95aced7216f5",
|
||||
"outputs/ispc-residuals-20261025/directed-known-exclusions.txt": "9c2e039af72cd3b46624979d1d07cae31ffc7f19572dfec1c279272dfdaee0dc",
|
||||
"outputs/ispc-residuals-20261025/directed-dispensation-form.txt": "ff6ab503c476af55e950937d99a40eb6591d7d479cfed60dcddc681dcf7421fb",
|
||||
"outputs/ispc-residuals-20261025/api.txt": "12ac172c5898f91ed9ac1bd0216265c33683e6984e817c5d6cb8759c1448b184",
|
||||
"outputs/ispc-residuals-20261025/types-package.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
|
||||
"outputs/ispc-residuals-20261025/build-package.txt": "d3b9271730c3e0e6dd87f770a7d7badeb7a5e25e76aac44877b4484078e037b4",
|
||||
"outputs/ispc-residuals-20261025/ui-own-report.txt": "c770078829e65c3830116c192d819c1f8327b8024806b841d88436219bb26571",
|
||||
"outputs/ispc-residuals-20261025/ui-acquisition-report.txt": "ce976d2042e8ab7f13c42c42b8bd13a32ad67a2eb64ccf408ddf7d20688f1534",
|
||||
"outputs/ispc-residuals-20261025/ui-occasional-applicability.txt": "72a3eee5b24c5b18faef1ab00076fb9e4d550b84daac41690dfc4488201311b8",
|
||||
"outputs/ispc-residuals-20261025/ui-regular-applicability.txt": "2fb06f6e9e845022a464c9ffcc1fdee66b3ee2566bfce811c3e63b02cef4ab0a",
|
||||
"outputs/ispc-residuals-20261025/preparation.html": "bd8dabebcc27b1e27df345648cf6b8fd5ce780f37d422d23f3689ef941f52cf1",
|
||||
"outputs/ispc-residuals-20261025/active-baseline.json": "ed1e4d9c09215f9695fad1e02e6efec4c5a7097c5c35f0425e3a5142e98f2bc1",
|
||||
"outputs/ispc-residuals-20261025/directed-liberatory-history.txt": "ec7836ece4ea47a5e5b039958f18ed0d00cd87af219e1ce3cad2316c7f36977d",
|
||||
"outputs/ispc-residuals-20261025/types-final.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
|
||||
"outputs/ispc-residuals-20261025/build-final.txt": "939ba2172a3b5360d909d36199887f34a9a654f2f4e57a19a12b9c763dd9ca92"
|
||||
},
|
||||
"preservation_audit": {
|
||||
"matrix_only_changed": "AUD-SIM-INT02",
|
||||
"L1_closed_preserved": 131,
|
||||
"original_PDFs_preserved": 17,
|
||||
"habitual_arithmetic_engines": "ispc-quarter.ts/ispc-withholding.ts byte-identical to6af7092e",
|
||||
"eligibility_regular_path": "byte-identical except message for occasional route",
|
||||
"source_scope_choices": "Separate books,concrete factinputs and exact cap intervals are implementation choices,not new organisational approvals;no generic legal/provenance revalidation."
|
||||
},
|
||||
"liberatory_history_guard": "Same operation reference/date/quarter/amount with documented prior liberatory withholding cannot generate another own payment without explicit correction reference; history preserved."
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"status": "prepared_compatible_QA_not_installed_fresh_authenticated_backup_restore_pending",
|
||||
"authorization": "Tempo25/10:avançarcoberturaL3QA,conferirapenasofaltanteepreparentregacompatível;depoissaldoL3eL4ISPC.",
|
||||
"status": "installed_and_delta_verified",
|
||||
"authorization": "Tempo25/10:entregarL3combackup/restaurofrescoeconferênciadodelta;L3mantémresiduaispróprios.",
|
||||
"base_installed": "7ad187f9f0745245268e3ed5317547a96b4700f3",
|
||||
"source_QA": "b189d0fa",
|
||||
"candidate_branch": "codex/l3-additional-delivery-20261025",
|
||||
@@ -262,5 +262,262 @@
|
||||
"SemcontacentralATpresumida,novaautoridadeoucondiçãoorganizacional.",
|
||||
"Preparação não equivale ainstalação;backup antigo nãoéprovafresca."
|
||||
],
|
||||
"active_writes": 0
|
||||
"active_writes": 0,
|
||||
"candidate_commit": "0f4df8a4d1cfd0d7b788e58d7f6af8d385384d82",
|
||||
"candidate_build_proof": "outputs/l3-additional-delivery-20261025/candidate-build-final.txt",
|
||||
"candidate_types_proof": "outputs/l3-additional-delivery-20261025/candidate-types.txt",
|
||||
"requested_candidate": "0f4df8a4d1cfd0d7b788e58d7f6af8d385384d82",
|
||||
"installed_commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"compatibility_correction": {
|
||||
"requested_candidate": "0f4df8a4",
|
||||
"actual_target": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"delta": "tests/frontend/iva-l1-delta.test.mjs only; obsolete text assertions updated to accepted P001 residual. No fiscal/runtime/schema/config/data changes.",
|
||||
"new_evidence": "pipeline756/757;singlefailurelegacywording",
|
||||
"directed_verification": "1passed;legacy-assertion.txt",
|
||||
"P001": "remainsresidual;no functional expansion or research"
|
||||
},
|
||||
"authenticated_backup": {
|
||||
"stage": "/var/backups/investmoz-l3-additional-delivery-20261025/backup",
|
||||
"target": {
|
||||
"database": "teste_investidor",
|
||||
"port": 5432
|
||||
},
|
||||
"tables": 174,
|
||||
"files_verified": 369,
|
||||
"dump_sha256": "ef95cc22d9c5c6b924309fa8c7654a42d7afe67e26b0c118903f507dd2693d0e",
|
||||
"files_sha256": "b60d64adfc99ed51621ace3d8b273bf3c723978cf8dd08b16c61fab5a3dfb0e3",
|
||||
"restore_verified": false
|
||||
},
|
||||
"isolated_restore": {
|
||||
"restore_verified": true,
|
||||
"tables_verified": 174,
|
||||
"container_network": "none",
|
||||
"database": "l3_additional_restore_20261025",
|
||||
"port": 55441,
|
||||
"source_dump_sha256": "ef95cc22d9c5c6b924309fa8c7654a42d7afe67e26b0c118903f507dd2693d0e",
|
||||
"active_database_writes": 0
|
||||
},
|
||||
"installed_preservation": {
|
||||
"installed": {
|
||||
"status": "installed",
|
||||
"commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"release": "/var/www/investmoz-homologacao/releases/fa32a2b9e127da9c4d764dd99ef58ee43b770aa6-ad33eeab",
|
||||
"previous_release": "/var/www/investmoz-homologacao/releases/7ad187f9f0745245268e3ed5317547a96b4700f3-066618f1",
|
||||
"database_migrations": 0,
|
||||
"content_imports": 0
|
||||
},
|
||||
"runtime_files_verified": 12,
|
||||
"documentary_files_verified": 17,
|
||||
"persistent_files_and_env_verified": 369,
|
||||
"tables_compared": 174,
|
||||
"changed_tables": {
|
||||
"cache": {
|
||||
"before": {
|
||||
"rows": 106,
|
||||
"checksum": "8ba41882cd8a7068c45619b3234af395"
|
||||
},
|
||||
"after": {
|
||||
"rows": 106,
|
||||
"checksum": "e2140cc9610defc5e64743159fb4df57"
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"before": {
|
||||
"rows": 153,
|
||||
"checksum": "66a8c21d1167a5c4ef27e205006736d4"
|
||||
},
|
||||
"after": {
|
||||
"rows": 154,
|
||||
"checksum": "6bd8d1311dcc20736dacc02873316399"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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
|
||||
},
|
||||
"installed_public": {
|
||||
"status": "installed_delta_verified",
|
||||
"served_revision": {
|
||||
"commit": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"branch": "main",
|
||||
"built_at": "2026-10-25T15:12:37.806036+00:00",
|
||||
"manifest_sha256": "cddac25dc66b3e555f2380cf3a9d4b2da6501cd03927c183c832a05b0ee5c993"
|
||||
},
|
||||
"manifest_hash_matches": true,
|
||||
"compiled_delta_markers": {
|
||||
"Repartição do IVA documental em MZN": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Reconciliação da dedução anterior": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Cálculos indeterminados e condições para resolver": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Preparação dos quadros L3 e formalidades": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Calcular e guardar restituição E": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Calcular e guardar acompanhamento D": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
],
|
||||
"Calcular e guardar substituições C": [
|
||||
"assets/services-Yy7oCdim.js"
|
||||
]
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"file": "assets/project-dossier-document-DEYq4rSm.js",
|
||||
"status": 200,
|
||||
"sha256": "76e21fbdb32395a7208023b171208a278d966a726ca5da75616eb4895f900085"
|
||||
},
|
||||
{
|
||||
"file": "assets/services-Yy7oCdim.js",
|
||||
"status": 200,
|
||||
"sha256": "fcccdac290664ac7ab03656f2b82fc412d558352611f96d356d0fa6b82eabee8"
|
||||
},
|
||||
{
|
||||
"file": "assets/simulation-form-BqVD91Ek.js",
|
||||
"status": 200,
|
||||
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
|
||||
},
|
||||
{
|
||||
"file": "assets/project-dossier-BFOK3ylo.js",
|
||||
"status": 200,
|
||||
"sha256": "ee9695ec2699120f5e9381d3e27384a6e4c969899f12659b75b47e7f8f3fa2ac"
|
||||
}
|
||||
],
|
||||
"simulator_status": 200,
|
||||
"simulator_entry": "assets/app-8LF5gm1q.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"
|
||||
},
|
||||
"build_dependency_archival": {
|
||||
"status": "dependencies_archived_and_verified",
|
||||
"versions": 11,
|
||||
"free_before": 4627697664,
|
||||
"free_after": 7521255424,
|
||||
"receipt": "/var/backups/investmoz-build-dependencies-20261025/receipt.json",
|
||||
"protected": [
|
||||
"/var/www/investmoz-homologacao/releases/de36f02880adf2337edf9f08c3eb424424adcca0-b247ef3c",
|
||||
"/var/www/investmoz-homologacao/releases/7ad187f9f0745245268e3ed5317547a96b4700f3-066618f1"
|
||||
],
|
||||
"active_or_previous_release_modified": false,
|
||||
"source_data_backups_deleted": 0
|
||||
},
|
||||
"operational_delta": {
|
||||
"status": "operational_delta_reconciled",
|
||||
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
|
||||
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
|
||||
"sessions": "anonymous sessions created by exact delivery verification user-agent",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessions": {
|
||||
"before_rows": 153,
|
||||
"after_rows": 156,
|
||||
"changes": [
|
||||
{
|
||||
"key_sha256": "9e2b645a40c93a4975977fd394b80496ecabd7a5b8ae17c259b4105f342e5937",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
},
|
||||
{
|
||||
"key_sha256": "1fbd25a79d44d1826aa3b95e1bf19c4268a56b0398ec74f3d4e5b7d5bc44c752",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
},
|
||||
{
|
||||
"key_sha256": "65497833fad3b62fd5f3982ff4c6c2770ffb0599616e57f917d38762b87cc59a",
|
||||
"kind": "added",
|
||||
"fields": [
|
||||
"id",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"payload",
|
||||
"last_activity"
|
||||
],
|
||||
"anonymous_user": true,
|
||||
"delivery_user_agent": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"business_tables_unchanged": 172,
|
||||
"active_data_writes_by_comparison": 0,
|
||||
"restore_network": "none"
|
||||
},
|
||||
"remaining_balance_reference": "l3-e-additional-coverage-qa-20261025.json:current_L3_balance_20261025"
|
||||
}
|
||||
|
||||
@@ -116,14 +116,14 @@
|
||||
]
|
||||
},
|
||||
"current_L3_balance_20261025": {
|
||||
"base_installed": "7ad187f9",
|
||||
"base_installed": "fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"QA_increment": "b189d0fa",
|
||||
"items": [
|
||||
{
|
||||
"item": "Entrega do incremento b189d0fa",
|
||||
"tipo": "disponibilização",
|
||||
"estado": "QA demonstrada;não instalada",
|
||||
"falta": "Entrega pelo processoGit existente,com comparação fresca do destino,backup/restauro e conferência do delta. Não repetir provas aceites sem alteração relevante."
|
||||
"estado": "Entregue e conferido no activo em fa32a2b9e127da9c4d764dd99ef58ee43b770aa6",
|
||||
"falta": "Nenhuma neste delta;backup/restauro fresco e conferência pública/protegida concluídos. Demais itensL3 mantidos com âmbitos próprios."
|
||||
},
|
||||
{
|
||||
"item": "Mudança/anulação de dedução anterior e versões divergentes",
|
||||
@@ -157,7 +157,9 @@
|
||||
}
|
||||
],
|
||||
"scope_limit": "A prevenção de duplicação cobre os livros/históricos recuperados. Reconciliação central com aAT ou todos os dossiers não foi demonstrada;isto é limite técnico registado,não nova condição organizacional de fecho.",
|
||||
"outside_L3": "L1:131entregues+P001residual+P058parcial/residual=133;P084/P085fechados. P001retomasócomnovoesclarecimentoconcreto;L2limitespróprios;estatísticas/IAadiadas."
|
||||
"outside_L3": "L1:131entregues+P001residual+P058parcial/residual=133;P084/P085fechados. P001retomasócomnovoesclarecimentoconcreto;L2limitespróprios;estatísticas/IAadiadas.",
|
||||
"prepared_candidate": "0f4df8a4d1cfd0d7b788e58d7f6af8d385384d82",
|
||||
"delivered_increment": "0f4df8a4 + fa32a2b9(test-only)"
|
||||
},
|
||||
"P001_followup": {
|
||||
"status": "residual_preserved_resume_only_on_concrete_clarification",
|
||||
|
||||
@@ -106,3 +106,14 @@ A pesquisa read-only no catálogo oficial da INM voltou a localizar o BR n.º 18
|
||||
Fontes oficiais: [catálogo INM — BR 186/187 e aviso de indisponibilidade gratuita](https://inm.gov.mz/pt-br/bulletin?field_tipo_de_produto_tid_br=43), [ficha BR 186](https://inm.gov.mz/pt-br/content/br-n%C2%BA-186-de-300926-boletim-da-rep%C3%BAblica-i-serie), [ficha BR 187](https://inm.gov.mz/pt-br/content/br-n%C2%BA-187-de-011026-boletim-da-rep%C3%BAblica-i-serie).
|
||||
|
||||
Estado: confirmação oficial apenas de existência, datas e modalidade de acesso; textos, diplomas, artigos, vigência, transição e âmbito fiscal continuam por confirmar. Manter IRPC, IRPS, ISPC, IVA regulamentar, pautas/cálculos aduaneiros e regras contributivas sem activação até obtenção, análise e aprovação competente.
|
||||
|
||||
## 25/10/2026 — fontes adicionais dos residuais ISPC
|
||||
|
||||
Inventários oficiais AT guardados antes da selecção:39formulários,189documentos legislativos e4comunicados. O Comunicado9/2026 e os exemplares B–Geral/Modelo30 foram recuperados pela ligação pública do próprio portalAT. A republicaçãoIRPS19/2017 é exemplar do BR202/7.ºsuplemento,disponibilizado pelaOCAM;arts8/9naPDF4 e57naPDF13 foram conferidos visualmente,com alteração2026confrontada naLei11/2025. O código local mais antigo não foi usado para a numeração dos actos isolados. A aceitação oficial mantém-se,sem segunda validação de proveniência.
|
||||
|
||||
- `AT-Comunicado-9-2026-ISPC.pdf` — SHA256 `106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973`;original preservado emsource-archive,sem publicação/activação automática.
|
||||
- `AT-Modelo-B-Geral.pdf` — SHA256 `bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57`;original preservado emsource-archive,sem publicação/activação automática.
|
||||
- `AT-Modelo-30-ISPC.pdf` — SHA256 `6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c`;original preservado emsource-archive,sem publicação/activação automática.
|
||||
- `Lei-19-2017-IRPS-BR-OCAM.pdf` — SHA256 `c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d`;original preservado emsource-archive,sem publicação/activação automática.
|
||||
|
||||
Uso:comunicadoATindicaB–Geraltransitório;campos correspondidos por quadro. Modelo30aindacontém75.000/3%antigos epermaneceexcluído dos cálculos2026. IRPS57(2k,4)suporta20%sobre rendimentoilíquido de acto isolado qualificado,nãotaxagenérica de compras excedentes. Citações,URLs ehashes completos no recibo ispc-residuals-qa-20261025.json. Scan/vigência global não foram certificados por esta importação privada.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5754,3 +5754,71 @@ A identificação do exemplar e o critério deaceitação já foram definidos pe
|
||||
DecisãoTempo:P001ficaresidual,provaspreservadasesematribuiçãoautomática06;retomaapenascomesclarecimentoconcretonovo.P058mantémâmbitoparcialdisponíveleexclusõesidentificadas.P084/P085mantêmfechooperacional.Avance:coberturaadicionalL3b189d0faQA,conferirapenasofaltanteepreparentregacompatível;reconciliarsaldoL3edepoisL4ISPCconformeplanoexistente.Semrepetirpesquisa/testesdosmesmospontossemnovainformação.Limitaçõesvisíveisnãoimpedempercursosindependentes.
|
||||
|
||||
CandidataisoladaemC:/laragon/www/portal-investidor-l3-qa-20261025,ramoscodex/l3-additional-delivery-20261025,baseb189d0fa/7ad187f9;provas43frontend/API1-105reutilizadas,nova conferência apenas dehashes,compatibilidadeecompilação. Preparação nãoéinstalação;execuçãoexigecomparaçãoautenticadaebackup/restauro fresco.
|
||||
|
||||
CandidataL3preparada:`0f4df8a4`,ramo`codex/l3-additional-delivery-20261025`. Buildetipos passaram;12ficheirosdedelta(10funcionaisjáaceites+2textosdelimitaçãoP001),7marcadorescompilados,schemas/PHP/configurações/dependênciassemalterações. Main/manifestopúblicoconferidosem7ad187f9;simuladorHTTP200. Scriptsprivadosdepreflight,backup/restauro,conferênciaprotegidaepúblicapreparadoscomguardasdenovoestado. Nenhumteste funcionalrepetido,nenhumaescritaactiva. Próximaexecuçãodaentrega:comparaçãoautenticadafresca,backup/restaurorealeconferênciadodelta. Não declararinstaladopelapreparação.
|
||||
|
||||
## 25/10/2026 — inícioL4-AISPCdepoisdapreparaçãoL3
|
||||
|
||||
L3candidata0f4df8a4preparada,provasaceitesreutilizadas;entregaefectivaexigepreflightautenticadoebackup/restaurofresco. SaldoL3mantémregularizaçõessequenciais/estornos,apuramentospróprios eformalidadesC/D/E;limitecontacentralATnãoénovacondiçãoorganizacional. NenhumresidualP001/P058bloqueiaL4.131fechosL1eP084/P085preservadosantesdosnovostestes. Acervofiscal/legislação/anexosacessíveisinventariadosemoutputs/ispc-l4a-20261025/preservation-before-tests.json.
|
||||
|
||||
L4-Aprimeiroincremento:enquadramentoelegibilidade2026,MZN,territórionacional,tipodepessoa,actividade,referênciaanual/prévisão,incompatibilidadesarts2–5,opçãoseparada.Reutilizarcamposválidosepreservarediçõesdeliberadas. Lei9/2025republicadaéfonteaceite;nenhumaaprovaçãogenéricaFiscalistaécriadacomoetapa. Apuramentotrimestral,escalões/excesso,mínimo/retençõeseformalidadescontinuamtrabalhopróprioL4seguinte;nenhumimpostocalculadoouregimeadoptadopelainventariação.
|
||||
|
||||
## 25/10/2026 — L4-A ISPC: primeiro incremento QA
|
||||
|
||||
Implementado enquadramento preliminar2026/MZN da actividade habitual pelos arts2–5 da Lei9/2025: referência anterior2025 ou previsão de início2026,limite4.000.000 inclusivo,incompatibilidades e dados concretos em falta. Regra183dias restrita aos serviços8(1)c. Opção permanece separada;seleccionarISPC não adopta regime. Perfil reutilizado com prévia e confirmação das divergências,edições deliberadas e outros livros preservados. Livro por contexto e histórico integrado no relatório existente.
|
||||
|
||||
Provas novas:12testesfrontend,tipos/build exit0. Não foram repetidos os testes aceites deL1/L2/L3/P001. Serialização/recuperação cobertas nos novos testes;transporte privado existente reutilizado. Demonstração visual integrada e gravação privada deste incremento continuam antes de propor entregaL4;nenhuma escrita activa. Recibo:ispc-l4a-eligibility-qa-20261025.json.
|
||||
|
||||
L4 continua aberto:apuramento trimestral,escalões e actividades mistas/excesso,mínimo500,retenção5%,percurso ocasional e formalidades próprias. As correspondências concretas serão tratadas no incremento seguinte,sem aprovação jurídica genérica ou bloqueio pelos residuaisP001/P058. L3 permanece aberto com candidata0f4df8a4 preparada e execução autenticada/backup-restauro por realizar. P084/P085 fechados;estatísticas/IA adiadas.
|
||||
|
||||
## 25/10/2026 — L4 ISPC: apuramento trimestral e percurso demonstrado em QA
|
||||
|
||||
O enquadramento e a opção guardados alimentam o apuramento trimestral de 2026 em MZN. O volume anual de acesso anterior, o volume anual do escalão e a base trimestral são distintos. Calculam-se as taxas de 3/4/5%, os serviços a 12/15%, a cumulação pela taxa maior e o excesso a 20%, com valores racionais exactos. O acumulado anterior impede repetir o excesso. O ano encerrado reconcilia os quatro trimestres; uma previsão permanece cenário. A prestação inferior a 500 MZN dispensa pagamento e conserva a declaração; exactamente 500 MZN mantém pagamento. A retenção de 5% nas aquisições ocasionais do artigo 12(3–4) tem livro e limite global de 2.500.000 MZN próprios, sem reduzir o imposto do adquirente.
|
||||
|
||||
Percurso demonstrado com componentes reais: elegibilidade/opção → cálculo → gravação → recuperação → relatório financeiro. Exemplo do T2: base de 200.000 MZN, taxa de 12%, imposto/prestação de 24.000 MZN e opção documentada em 01/01/2026. A API privada em QA passou 1 teste com 21 asserções, rollback e recusa de acesso a outra conta (404); os livros anteriores foram preservados exactamente. Passaram 13 testes novos (10 trimestrais e 3 de retenção), tipos e compilação. As fontes, provas aceites de L1/L2/L3/P001 e os 12 testes de L4-A foram reutilizados. Recibo: ispc-l4-quarterly-qa-20261025.json; provas: outputs/ispc-l4b-20261025.
|
||||
|
||||
O âmbito habitual trimestral está demonstrado em QA, ainda não instalado. O saldo de L4 fica delimitado às operações ocasionais próprias do artigo 3(3–4), às aquisições acima do limite global e à correspondência de formulários, instruções e regulamentação de 2026. O aviso primário do Governo sobre a aprovação de novo regulamento não fornece o articulado nem o modelo. Não se inventam formulários, prazos ou aprovadores; essas dependências não bloqueiam o cálculo habitual demonstrado. P001/P058 permanecem residuais e não interrompem a sequência; P084/P085 permanecem fechados.
|
||||
|
||||
## 25/10/2026 — entrega adicional de L3 com preservação conferida
|
||||
|
||||
O incremento de `0f4df8a4` foi instalado em `fa32a2b9`. Este descendente altera apenas a asserção de texto de um teste legado para o estado residual de P001 acordado; os cálculos e os 12 ficheiros runtime preparados mantêm os mesmos hashes. A referência de entrega conserva o candidato original e a correcção de compatibilidade. Backup fresco de 174 tabelas e 369 ficheiros, restauro isolado sem rede e comparação protegida com a mesma identidade confirmados. Nenhuma migração, importação de conteúdo ou alteração das 172 tabelas de negócio foi efectuada. Revisão/manifesto, sete marcadores compilados e simulador HTTP200 conferidos. As diferenças em cache correspondem ao reinício da fila e ao par contador/temporizador de limitação de pedidos; as sessões novas são anónimas e têm o agente das verificações de entrega.
|
||||
|
||||
A falta de espaço foi resolvida pela compactação verificada das dependências de construção de 11 versões antigas, conservadas em arquivo com hashes, ficheiros e ligações conferidos. A versão activa e a anterior não foram compactadas. Originais, código, backups, dados e recibos permaneceram disponíveis. O processo Git existente executou os seus controlos obrigatórios; não houve nova ronda manual dos casos funcionais aceites.
|
||||
|
||||
L3 continua aberto para regularizações sequenciais/reversões, apuramentos próprios de fornecimento/margem/viagens/eventos e formalidades C/D/E. Apenas esses casos dependentes ficam limitados. Preservam-se 16 MZN de IVA documental, zero de dedução nesta via, 12 reconhecidos, 7 recebidos e 5 por receber. P001 residual, P058 parcial e P084/P085 fechados mantêm os seus estados. L4 habitual trimestral está demonstrado em QA e não foi instalado. Recibo: l3-additional-delivery-20261025.json.
|
||||
|
||||
## 25/10/2026 — preparação Git da entrega L4 trimestral habitual
|
||||
|
||||
O candidato `6af7092e` foi preparado e publicado apenas no ramo `codex/ispc-l4-quarterly-qa-20261025`, sobre L3 instalado em `fa32a2b9`. O ramo principal e a revisão pública foram conferidos nesta base e não foram alterados. O bundle foi verificado. A comparação identificou nove ficheiros de aplicação: as três integrações existentes receberam apenas adições (6+6+1 linhas); onze ficheiros próprios de L3 e dezassete originais permanecem exactamente iguais. Os cinco marcadores compilados de L4 e os sete de L3 estão presentes. Não há delta de schema, PHP de aplicação, configuração ou dependências; o PHP acrescentado é apenas teste QA. O código experimental de P001 ficou excluído.
|
||||
|
||||
As provas QA aceites de cálculo, gravação privada, recuperação e relatório, assim como tipos e compilação da composição compatível, foram reutilizadas pelos respectivos hashes. Não houve nova ronda funcional. Prepararam-se os scripts guardados de comparação autenticada, backup, restauro isolado, integração Git sem force-push e conferência pública/protegida. Backup/restauro fresco e conferência de espaço continuam necessários na execução; o backup de L3 não foi apresentado como backup novo de L4. Esta preparação não instalou L4 nem alterou dados activos. Recibo: `ispc-l4-prepared-delivery-20261025.json`; pacote: `outputs/ispc-l4-delivery-20261025`.
|
||||
|
||||
L4 não fica integralmente concluído. Operações ocasionais próprias, aquisições acima do limite e formalidades de 2026 conservam os âmbitos e condições concretas registados. L3 mantém o saldo residual e a separação de 16 MZN documentais, zero de dedução nesta via, 12 reconhecidos, 7 recebidos e 5 por receber. P001/P058 aguardam os esclarecimentos previstos sem bloquear a entrega; P084/P085 permanecem fechados. Estatísticas e IA permanecem adiadas.
|
||||
|
||||
## 25/10/2026 — instalação do âmbito ISPC trimestral habitual
|
||||
|
||||
O candidato `6af7092e` foi integrado pelo Git e instalado sobre `fa32a2b9`. Foram conferidos backup/restauro fresco e isolado, nove ficheiros de aplicação de L4, onze ficheiros de L3 sem alteração, dezassete originais e os doze marcadores compilados de L4/L3. Os ficheiros persistentes e a configuração conservam os hashes do backup; as tabelas de negócio foram comparadas com a mesma identidade e contexto, sem inferir perda a partir de RLS. Diferenças operacionais de cache/sessões ficam explicitadas no recibo. Não houve migrações ou importações de conteúdo. As provas QA aceites foram reutilizadas; apenas os controlos obrigatórios do processo Git existente voltaram a executar, sem nova ronda manual.
|
||||
|
||||
Para assegurar espaço, dependências de construção de versões antigas foram compactadas em arquivo e verificadas antes de libertar a cópia descompactada. Versões activa e anterior, dados, originais, configurações e backups foram preservados. O recibo discrimina o arquivo e os respectivos controlos.
|
||||
|
||||
A equipa pode avaliar no portal o percurso habitual: elegibilidade/opção → cálculo trimestral → gravação → recuperação → relatório. O exemplo demonstrado mantém base de 200.000 MZN, taxa de 12% e imposto/prestação de 24.000 MZN. O ISPC não é apresentado como integralmente concluído: operações ocasionais próprias, aquisições acima do limite e formalidades de 2026 permanecem discriminadas. L3 e os seus residuais ficam preservados, incluindo 16 MZN documentais, zero de dedução nesta via, 12 reconhecidos, 7 recebidos e 5 por receber. P001/P058 aguardam os esclarecimentos previstos sem bloquear a sequência; P084/P085 permanecem fechados. Estatísticas e IA continuam adiadas. Recibo: `ispc-l4-delivery-20261025.json`.
|
||||
|
||||
## 25/10/2026 — inventário anterior ao delta residual ISPC
|
||||
|
||||
Antes dos testes novos, foram recuperadas as provas do percurso habitual instalado em6af7092e, L3 e os131fechos deL1; não há perdas confirmadas. P001/P058 eP084/P085 mantêm estados. O inventário local anterior foi reutilizado e os novos directórios oficiais daAT foram inventariados antes da selecção. O delta QA separa operações ocasionais próprias, cálculo das aquisições acima do limite e formalidades externas. Fontes novas: comunicadoAT9/2026 e exemplares B–Geral/Modelo30; republicaçãoIRPS19/2017 para incidência de actos isolados e taxa57(2)k, sem nova validação genérica. Não há alteração activa.
|
||||
|
||||
## 25/10/2026 — residuais ISPC agrupados em QA
|
||||
|
||||
Os três pontos foram tratados num delta compatível sobre o instalado `6af7092e`. Nas operações ocasionais próprias, o percurso distingue pessoa singular sem actividade habitual, acto imprevisível/não reiterado, operação nacional e famílias do artigo3(4); a correspondência positiva IRPS8(3h,4)/9 está identificada. A liquidação própria ISPC é separada da retenção liberatória comprovada: esta não gera segunda liquidação nem crédito duplicado. O exemplo próprio de100.000MZN a3%produz3.000MZN, mantendo opção documentada e pressupostos de projecção distintos.
|
||||
|
||||
Nas aquisições, acumulado de2.400.000MZN mais aquisição de200.000MZN separa100.000até ao limite e100.000excedentes. A primeira parcela conserva5.000MZN a5%. A parcela excedente não adquire taxa apenas pela ultrapassagem: o caso positivo implementado é acto isoladoIRPS57(2k), sem opçãoISPCaplicável e com rendimento ilíquido identificado, produzindo20.000MZN. As retenções são distintas e não reduzem o imposto próprio do adquirente. Enquadramento desconhecido ou fornecedor com opçãoISPC não recebem automaticamente5%ou20%. Vendedor/contexto376 e adquirente/contexto375 foram demonstrados separadamente.
|
||||
|
||||
As formalidades apoiam-se agora no ComunicadoAT9/2026 e no original B–Geral de duas páginas. Foram preparados os quadros1/2/3/5/6/8/10 e exportaçãoHTML, com identificadores de campo próprios de cada quadro; o Modelo30 ainda com75.000/3%antigos foi preservado e excluído do cálculo2026. O mês do período não é copiado do mês de pagamento. Submissão, recepção e pagamento ficam como actos externos declarados, com referências e histórico, sem os executar ou certificar.
|
||||
|
||||
O saldo separa cálculos de formalidades: juros compensatórios continuam sem fórmula por falta de regra/taxa/base/período aplicáveis; só montante documentado é conservado. Outros enquadramentos da parcela excedente exigem os seus dados e regra próprios, sem taxa genérica. Externamente faltam a correspondência concreta do período do quadro2, o modelo/código de entrega das retençõesISPC/IRPS e as instruções específicas2026 ainda não fornecidas. Identidade/NUIT/endereço/juros do caso sintético são dados da operação, não condição nova de acesso ao cálculo. Nenhuma dessas pendências bloqueia os casos positivos implementados.
|
||||
|
||||
Provas do delta:19testes novos distintos, APIprivadaQA1/22 comrollback, tipos e compilação, componentes reais com gravação/recuperação/relatório e preparaçãoHTML. O percurso habitual não foi recalculado: motores trimestral e de retenção existentes estão inalterados; o resultado de24.000MZN foi preservado exactamente. Conferiu-se apenas a visibilidade afectada: no modo ocasional os controlos habituais/do adquirente ficam ocultos com explicação e histórico; no contexto habitual continuam disponíveis. L3,17originais anteriores e131fechosL1foram preservados;P001/P058nãointerrompem eP084/P085permanecemfechados. QA não é instalação nem fecho integralISPC. Recibo:`ispc-residuals-qa-20261025.json`.
|
||||
|
||||
Na representação do B–Geral, a dispensa inferior a500MZN permanece uma correspondência formal específica: imposto calculado e prestação zero são mostrados separadamente, sem preencher o montante apurado como zero. O código não inventa a instrução de preenchimento. Este ponto não altera nem bloqueia o cálculo10-Ajá demonstrado.
|
||||
|
||||
Uma retenção liberatória documentada na mesma operação permanece no histórico e impede nova prestação própria sem referência concreta de correcção; mudar apenas a opção de liquidação não apaga o benefício anterior. Caso dirigido adicional aceite.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,7 @@
|
||||
import {SimulationIspcResiduals} from '@/components/simulation-ispc-residuals';
|
||||
import {SimulationIspcWithholding} from '@/components/simulation-ispc-withholding';
|
||||
import {SimulationIspcQuarter} from '@/components/simulation-ispc-quarter';
|
||||
import {SimulationIspcEligibility} from './simulation-ispc-eligibility';
|
||||
import { simulationDraftEtag } from '@/lib/simulation-draft-etag';
|
||||
import { SimulationPublishedIva, type PublishedIvaInput } from './simulation-published-iva';
|
||||
import { SimulationMonthlyIva } from './simulation-monthly-iva';
|
||||
@@ -3501,6 +3505,10 @@ export function SimulationForm() {
|
||||
onCurrencyChange={(value) => change('currency', value)}
|
||||
/></details>
|
||||
)}
|
||||
{(current.id === 'financial' || current.id === 'tax') && <SimulationIspcEligibility draft={draft} onChange={change} />}
|
||||
{(current.id === 'financial' || current.id === 'tax') && <SimulationIspcQuarter draft={draft} onChange={change} />}
|
||||
{(current.id === 'financial' || current.id === 'tax') && <SimulationIspcWithholding draft={draft} onChange={change} />}
|
||||
{(current.id === 'financial' || current.id === 'tax') && <SimulationIspcResiduals draft={draft} onChange={change} />}
|
||||
{(current.id === 'financial' || current.id === 'tax') && <SimulationMonthlyIva draft={draft} busy={isCalculating} onCalculate={runSimulation} onChange={change} />}
|
||||
{current.id === 'financial' &&
|
||||
(draft.detail_level === 'advanced' ||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import {useState} from 'react';
|
||||
import {ispcActivities,ispcEligibilityBook,saveIspcEligibilityBook,recordIspcEligibility,ispcEligibilityCurrent,ispcReuseDiff,ispcEligibilityReportRows,type IspcEligibilityInput,type IspcEligibilityBook} from '@/lib/ispc-eligibility';
|
||||
const factLabels:Partial<Record<keyof IspcEligibilityInput,string>>={territory:'Exerce a actividade em território nacional',organizedRequired:'Está obrigado a possuir contabilidade organizada para os impostos sobre o rendimento',sharesInIspc:'Tem participações noutras sociedades comerciais em ISPC',sharesAnonymous:'Tem participações em sociedades anónimas ou sociedades cujos sócios não são identificáveis',otherActivities:'Exerce outras actividades fora dos âmbitos identificados',unlistedServices:'Presta serviços fora dos previstos na Lei',forecastConfirmed:'Previsão da declaração de início confirmada pela AT (ou pressuposto expresso na simulação)',generalRegimeChosen:'Optou pela aplicação de IVA/IRPS/IRPC com permanência mínima de três anos',generalThreeYearsCompleted:'Já cumpriu o período mínimo de três anos dessa opção'};
|
||||
export function SimulationIspcEligibility({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
||||
const[error,setError]=useState(''),[reusePreview,setReusePreview]=useState<ReturnType<typeof ispcReuseDiff>|null>(null);if(draft.fiscal_component!=='ispc')return null;
|
||||
let book:IspcEligibilityBook;try{book=ispcEligibilityBook(draft);}catch(e){return<p role="alert">{String(e)}</p>;}
|
||||
const i=book.input,save=(next:IspcEligibilityBook)=>{try{onChange('modelo_a_snapshot',saveIspcEligibilityBook(draft,next));setError('');}catch(e){setError(String(e));}},change=(patch:Partial<IspcEligibilityInput>)=>save({...book,input:{...i,...patch}}),diff=ispcReuseDiff(draft,book),service=i.activities.some(a=>['services12','liberal15'].includes(a)),liberal=i.activities.includes('liberal15'),earlyOutside=i.activities.includes('other')||i.territory==='no'||i.mode==='occasional';
|
||||
const fact=(field:keyof typeof factLabels)=><label className="block" key={field}>{factLabels[field]}<select className="block rounded border p-2" value={String(i[field])} onChange={e=>change({[field]:e.target.value})}><option value="">Por esclarecer</option><option value="yes">Sim</option><option value="no">Não</option></select></label>;
|
||||
const text=(field:keyof IspcEligibilityInput,label:string,type='text')=><label className="block" key={field}>{label}<input className="block rounded border p-2" type={type} value={String(i[field])} onChange={e=>change({[field]:e.target.value})}/></label>;
|
||||
return<section aria-label="ISPC — enquadramento e opção" className="space-y-3 rounded border p-4"><h4 className="font-semibold">ISPC — enquadramento e opção</h4>
|
||||
<p>Avaliação preliminar para 2026, em MZN, segundo a Lei 9/2025. Distingue condições de acesso, opção e cálculo do imposto. Guarde esta avaliação e prossiga no apuramento trimestral abaixo.</p>
|
||||
{error&&<p role="alert">{error}</p>}
|
||||
{diff.length>0&&<button type="button" className="underline" onClick={()=>setReusePreview(diff)}>Conferir dados do perfil e da actividade para reutilizar</button>}
|
||||
{reusePreview&&<aside className="rounded border p-3"><p>A adopção altera as entradas deste cenário. O resultado guardado passa a histórico até novo cálculo; os outros livros e a opção registada são preservados.</p>{reusePreview.map(v=><p key={v.field}>{({personType:'Tipo de pessoa',establishments:'Estabelecimentos',activityDescription:'Actividade',entityRef:'Entidade'} as Record<string,string>)[v.field]??v.field}: {v.before||'Por preencher'} → {v.after}</p>)}<button type="button" onClick={()=>{change(Object.fromEntries(reusePreview.map(v=>[v.field,v.after])));setReusePreview(null);}}>Confirmar adopção destes dados</button><button type="button" onClick={()=>setReusePreview(null)}>Manter as minhas entradas</button></aside>}
|
||||
<div className="grid gap-3 md:grid-cols-2">{text('entityRef','Entidade de referência (reutilizável; sem NUIT obrigatório para preparar)')}
|
||||
<label>Tipo de pessoa<select className="block rounded border p-2" value={i.personType} onChange={e=>change({personType:e.target.value as IspcEligibilityInput['personType']})}><option value="">Por identificar</option><option value="singular">Pessoa singular</option><option value="collective">Pessoa colectiva</option></select></label>
|
||||
{text('assessmentDate','Data de avaliação','date')}
|
||||
<label>Natureza dos dados<select className="block rounded border p-2" value={i.origin} onChange={e=>change({origin:e.target.value as IspcEligibilityInput['origin']})}><option value="projected">Pressupostos da simulação</option><option value="effective">Dados efectivos declarados</option></select></label>
|
||||
<label>Moeda dos valores ISPC<select className="block rounded border p-2" value={i.currency} onChange={e=>change({currency:e.target.value})}><option value="">Por identificar</option><option value="MZN">MZN</option>{i.currency&&i.currency!=='MZN'&&<option value={i.currency}>{i.currency} — fora da cobertura deste cálculo</option>}</select></label>
|
||||
<label>Âmbito da preparação<select className="block rounded border p-2" value={i.mode} onChange={e=>change({mode:e.target.value as IspcEligibilityInput['mode']})}><option value="regular">Actividade habitual</option><option value="occasional">Operação ocasional — percurso próprio</option></select></label>
|
||||
{fact('territory')}</div>
|
||||
<fieldset className="space-y-2 rounded border p-3"><legend>Actividades do contribuinte</legend><p>Identifique todas as actividades, incluindo as exercidas fora desta oportunidade. Não inferimos o regime pelo sector ou pela nacionalidade.</p>{ispcActivities.map(([kind,label])=><label className="block" key={kind}><input type="checkbox" checked={i.activities.includes(kind)} onChange={e=>change({activities:e.target.checked?[...i.activities,kind]:i.activities.filter(a=>a!==kind)})}/> {label}</label>)}{text('activityDescription','Descrição da actividade e natureza dos serviços, quando existam')}</fieldset>
|
||||
{!earlyOutside&&<><fieldset className="grid gap-3 rounded border p-3 md:grid-cols-2"><legend>Volume anual de referência</legend><label>Referência de acesso<select className="block rounded border p-2" value={i.basis} onChange={e=>change({basis:e.target.value as IspcEligibilityInput['basis'],...(!i.referenceYear?{referenceYear:e.target.value==='previous_year'?'2025':e.target.value==='start_forecast'?'2026':''}:{})})}><option value="">Por identificar</option><option value="previous_year">Volume de negócios do ano anterior</option><option value="start_forecast">Previsão da declaração de início de actividade</option></select></label>{text('referenceYear','Ano do valor de referência')}{text('annualReference','Volume anual de referência em MZN')}{text('annualReferenceRef','Origem do valor ou pressuposto (opcional)')}<p className="md:col-span-2">Não copiar receita trimestral ou do ano em curso como receita do ano anterior. Alterar a origem não reinterpreta o valor já editado; reveja o montante e o ano.</p>{i.basis==='start_forecast'&&<>{fact('forecastConfirmed')}{text('forecastConfirmationRef','Referência da confirmação da previsão, se efectiva')}</>}</fieldset>
|
||||
<fieldset className="space-y-3 rounded border p-3"><legend>Condições aplicáveis ao contribuinte</legend>{text('establishments','Número de estabelecimentos da actividade, incluindo fora deste dossier')}{fact('organizedRequired')}{fact('sharesInIspc')}{fact('sharesAnonymous')}{fact('otherActivities')}{service&&fact('unlistedServices')}{liberal&&<>{text('liberalDaysSameEntity','Maior duração anual dos serviços à mesma entidade, em dias')}{text('liberalClientRef','Referência do cliente/contrato ou pressuposto da duração')}<p>O limite de 183 dias refere-se aos serviços do artigo 8(1)c. A permanência liberal tem limite próprio de cinco anos; a contagem transitória começa em 2026.</p></>}{fact('generalRegimeChosen')}{i.generalRegimeChosen==='yes'&&<>{fact('generalThreeYearsCompleted')}{text('generalRegimeRef','Referência da opção e do cumprimento dos três anos')}</>}</fieldset>
|
||||
<fieldset className="space-y-2 rounded border p-3"><legend>Opção — separada da compatibilidade</legend><label>Situação da opção<select className="block rounded border p-2" value={i.option} onChange={e=>change({option:e.target.value as IspcEligibilityInput['option']})}><option value="preparation">Em preparação — sem adesão automática</option><option value="opted">Opção registada no documento/cenário</option><option value="not_opted">Não optou pelo ISPC</option></select></label>{i.option==='opted'&&<>{text('optionReference','Referência da opção')}{text('optionDate','Data da opção','date')}</>}</fieldset></>}
|
||||
<button type="button" className="rounded bg-emerald-800 p-2 text-white" onClick={()=>{try{save(recordIspcEligibility(draft,book));}catch(e){setError(String(e));}}}>Avaliar e guardar enquadramento ISPC</button>
|
||||
{book.result&&<p role="status">{ispcEligibilityCurrent(draft,book)?'Resultado correspondente às entradas guardadas.':'Entradas alteradas; resultado histórico preservado. Reveja e guarde nova avaliação.'}</p>}
|
||||
{ispcEligibilityReportRows(draft).map((r,index)=><p key={index}><strong>{r[1]}:</strong> {r[2]}<small className="block">{r[3]}</small></p>)}
|
||||
</section>;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import {useState} from 'react';
|
||||
import {ispcEligibilityBook,ispcEligibilityCurrent} from '@/lib/ispc-eligibility';
|
||||
import {ispcQuarterBook,saveIspcQuarterBook,recordIspcQuarter,ispcQuarterReportRows,type IspcQuarterInput,type IspcQuarterBook} from '@/lib/ispc-quarter';
|
||||
export function SimulationIspcQuarter({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
||||
const[error,setError]=useState('');if(draft.fiscal_component!=='ispc')return null;
|
||||
try{if(ispcEligibilityBook(draft).input.mode==='occasional')return<p>Actividade habitual:campos trimestrais conservados no histórico. Use o percurso de operações ocasionais próprias abaixo.</p>;}catch{/* Preserve the existing explicit recovery error below. */}
|
||||
let book:IspcQuarterBook;try{book=ispcQuarterBook(draft);}catch(e){return<p role="alert">{String(e)}</p>;}
|
||||
const i=book.input,save=(b:IspcQuarterBook)=>{try{onChange('modelo_a_snapshot',saveIspcQuarterBook(draft,b));setError('');}catch(e){setError(String(e));}},change=(patch:Partial<IspcQuarterInput>)=>save({...book,input:{...i,...patch}});
|
||||
let service=false,ready=false;try{const e=ispcEligibilityBook(draft);ready=ispcEligibilityCurrent(draft,e)&&e.result?.status==='compatible';service=e.input.activities.some(a=>['services12','liberal15'].includes(a));}catch{/* Show explicit preparation issue below, never fabricate eligibility. */}
|
||||
return<section aria-label="Apuramento trimestral ISPC" className="space-y-3 rounded border p-4"><h4>ISPC — apuramento trimestral</h4><p>Reutiliza o enquadramento e a opção guardados. Declare o volume de todas as actividades do sujeito passivo em MZN; custos e IVA de aquisições não reduzem esta base. Dados em falta permanecem indeterminados.</p>{!ready&&<p>Reveja e guarde primeiro a avaliação de enquadramento acima. As entradas trimestrais e o histórico ficam conservados.</p>}{error&&<p role="alert">{error}</p>}
|
||||
<label className="block">Ano<input className="block rounded border p-2" value={i.year} onChange={e=>change({year:e.target.value})}/></label><label className="block">Trimestre<select className="block rounded border p-2" value={i.quarter} onChange={e=>change({quarter:e.target.value})}>{['1','2','3','4'].map(q=><option key={q} value={q}>{q} — {['Janeiro a Março','Abril a Junho','Julho a Setembro','Outubro a Dezembro'][Number(q)-1]}</option>)}</select></label>
|
||||
<label className="block">Âmbito do volume<select className="block rounded border p-2" value={i.coverage} onChange={e=>change({coverage:e.target.value as IspcQuarterInput['coverage']})}><option value="">Por confirmar</option><option value="all_taxpayer_activity">Todas as actividades do sujeito passivo, sem repetir oportunidades</option></select></label>
|
||||
<div className="grid gap-3 md:grid-cols-2">{i.sales.map((v,n)=>(n<Number(i.quarter)||i.annualBandOrigin==='closed_year'&&!service)&&<fieldset key={n} className="space-y-2 rounded border p-2"><legend>Trimestre {n+1}{n+1===Number(i.quarter)?' — a apurar':' — acumulado anterior'}</legend><label className="block">Volume T{n+1} em MZN<input className="block rounded border p-2" inputMode="decimal" value={v} onChange={e=>{const a=[...i.sales] as IspcQuarterInput['sales'];a[n]=e.target.value;change({sales:a});}}/></label><label className="block">Suporte ou pressuposto T{n+1}<input className="block rounded border p-2" value={i.salesRefs[n]} onChange={e=>{const a=[...i.salesRefs] as IspcQuarterInput['salesRefs'];a[n]=e.target.value;change({salesRefs:a});}}/></label></fieldset>)}</div>
|
||||
{!service&&<fieldset className="space-y-2 rounded border p-3"><legend>Escalão anual da actividade — distinto do volume de acesso</legend><p>Os limites de 1.000.000 / 2.500.000 / 4.000.000 MZN são anuais. A taxa do escalão é aplicada à base do trimestre; não dividir os limites por quatro. O excesso anual tem taxa própria de 20%.</p><label className="block">Volume anual 2026 para o escalão<input className="block rounded border p-2" value={i.annualBandVolume} onChange={e=>change({annualBandVolume:e.target.value})}/></label><label className="block">Origem da referência anual<select className="block rounded border p-2" value={i.annualBandOrigin} onChange={e=>change({annualBandOrigin:e.target.value as IspcQuarterInput['annualBandOrigin']})}><option value="">Por identificar</option><option value="forecast">Previsão expressa — simulação</option><option value="closed_year">Ano encerrado — reconciliar quatro trimestres</option></select></label><label className="block">Suporte da referência anual<input className="block rounded border p-2" value={i.annualBandRef} onChange={e=>change({annualBandRef:e.target.value})}/></label></fieldset>}
|
||||
<button type="button" className="rounded bg-emerald-800 p-2 text-white" onClick={()=>{try{save(recordIspcQuarter(draft,book));}catch(e){setError(String(e));}}}>Calcular e guardar apuramento trimestral ISPC</button>
|
||||
{ispcQuarterReportRows(draft).map((r,n)=><p key={n}><strong>{r[1]}:</strong> {r[2]}<small className="block">{r[3]}</small></p>)}
|
||||
<p>Preparação para a declaração periódica dos artigos 10/11. Este cálculo não submete formulários nem efectua pagamentos. Retenção na fonte em aquisições ocasionais tem registo e base próprios.</p></section>;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import {useState} from 'react';
|
||||
import {ispcEligibilityBook} from '@/lib/ispc-eligibility';
|
||||
import {ispcWithholdingBook} from '@/lib/ispc-withholding';
|
||||
import {decimalFraction,addFractions} from '@/lib/fiscal-rational';
|
||||
import {ispcResidualBook,saveIspcResidualBook,recordIspcResidual,priorOccasionalSettlement,ispcResidualReportRows,ispcFormalPreparationHtml,type ResidualKind} from '@/lib/ispc-residuals';
|
||||
export function SimulationIspcResiduals({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
||||
const[error,setError]=useState('');if(draft.fiscal_component!=='ispc')return null;
|
||||
try{
|
||||
const own=ispcResidualBook(draft,'occasional'),acq=ispcResidualBook(draft,'acquisitions'),formal=ispcResidualBook(draft,'formalities'),e=ispcEligibilityBook(draft),w=ispcWithholdingBook(draft);let above=false;try{const sum=addFractions([decimalFraction(w.input.base),decimalFraction(w.input.priorAnnualPurchases)]);above=BigInt(sum.numerator)>2500000n*BigInt(sum.denominator);}catch{/* Unknown is still handled in existing acquisition panel. */}
|
||||
const book=(k:ResidualKind)=>k==='occasional'?own:k==='acquisitions'?acq:formal;
|
||||
const change=(k:ResidualKind,p:Record<string,string>)=>{const b=book(k);onChange('modelo_a_snapshot',saveIspcResidualBook(draft,{...b,input:{...b.input,...p}}));};
|
||||
const field=(k:ResidualKind,n:string,label:string,type='text')=><label key={n} className="block">{label}<input className="block rounded border p-2" type={type} value={book(k).input[n]??''} onChange={ev=>change(k,{[n]:ev.target.value})}/></label>;
|
||||
const select=(k:ResidualKind,n:string,label:string,options:Array<[string,string]>)=><label key={n} className="block">{label}<select className="block rounded border p-2" value={book(k).input[n]??''} onChange={ev=>change(k,{[n]:ev.target.value})}>{options.map(([v,l])=><option key={v} value={v}>{l}</option>)}</select></label>;
|
||||
const yesno=(k:ResidualKind,n:string,label:string)=>select(k,n,label,[['','Por esclarecer'],['yes','Sim'],['no','Não']]);
|
||||
const save=(k:ResidualKind)=>{try{onChange('modelo_a_snapshot',saveIspcResidualBook(draft,recordIspcResidual(draft,book(k))));setError('');}catch(err){setError(String(err));}};
|
||||
const activities:Array<[string,string]>=[['','Por identificar'],['forestry','Silvícola'],['fishery','Pesqueira'],['livestock','Pecuária'],['agriculture','Agrícola'],['poultry','Avícola'],['beekeeping','Apícola'],['other','Outra—fora do recorte ocasional']];
|
||||
return<section aria-label="ISPC — operações ocasionais, limite e formalidades" className="space-y-4">{error&&<p role="alert">{error}</p>}
|
||||
{e.input.mode==='occasional'&&<section className="space-y-3 rounded border p-4"><h4>Operações ocasionais próprias</h4><p>Percurso do vendedor ocasional, distinto da retenção feita pelo comprador. Uma retenção liberatória comprovada não gera segunda liquidação própria.</p>{select('occasional','personType','Tipo de pessoa destas operações',[['','Por identificar'],['singular','Pessoa singular'],['collective','Pessoa colectiva']])}{select('occasional','origin','Natureza dos dados',[['projected','Pressupostos de simulação'],['effective','Factos efectivos declarados']])}{field('occasional','currency','Moeda—MZN')}{field('occasional','operationDate','Data das operações','date')}{select('occasional','quarter','Trimestre2026',[['','Por identificar'],['1','1'],['2','2'],['3','3'],['4','4']])}{yesno('occasional','territory','Operação realizada em território nacional')}{yesno('occasional','noHabitual','Não exerce actividade habitual')}{yesno('occasional','sporadic','Acto não previsível nem reiterado')}{select('occasional','activity','Natureza da operação',activities)}{field('occasional','reference','Documentos ou pressupostos da operação')}{field('occasional','amount','Volume de todas estas operações do trimestre em MZN')}{select('occasional','settlement','Via aplicável',[['','Por identificar'],['self','Liquidação própria por opção ISPC'],['withheld','Retenção liberatória documentada pelo adquirente']])}
|
||||
{own.input.settlement==='self'&&<>{yesno('occasional','allQuarterOperations','Inclui todas as operações ocasionais do sujeito passivo no trimestre')}{field('occasional','priorYearTurnover','Volume de referência2025 para acesso, incluindo zero expresso')}{field('occasional','priorYearRef','Suporte da referência2025')}{yesno('occasional','organizedRequired','Obrigado a contabilidade organizada para impostos sobre rendimento')}{select('occasional','option','Opção para estas operações',[['preparation','Em preparação—apenas cenário'],['opted','Opção documentada'],['not_opted','Não optou']])}{own.input.option==='opted'&&<>{field('occasional','optionRef','Referência da opção')}{field('occasional','optionDate','Data da opção','date')}</>}{field('occasional','annual2026','Volume anual2026 para escalão')}{select('occasional','annualOrigin','Origem do volume anual2026',[['','Por identificar'],['forecast','Previsão—cenário'],['closed_year','Volume anual encerrado documentado']])}{field('occasional','annualRef','Suporte ou pressuposto do volume anual2026')}{field('occasional','priorInYear','Volume de operações anteriores no ano2026')}{priorOccasionalSettlement(own)&&<><p>Existe retenção liberatória guardada para esta operação. A mudança de via não a apaga nem gera uma segunda prestação.</p>{yesno('occasional','withholdingCorrected','Retenção anterior corrigida/anulada segundo documento externo')}{field('occasional','withholdingCorrectionRef','Referência externa da correcção da retenção anterior')}</>}</>}
|
||||
{own.input.settlement==='withheld'&&<>{yesno('occasional','buyerIspc','Adquirente sujeito passivo ISPC')}{yesno('occasional','unregistered','Vendedor não inscrito para tributação')}{field('occasional','buyerAnnualPurchases','Aquisições globais anuais do adquirente, incluindo estas operações')}{field('occasional','withheldActual','Montante efectivamente retido em MZN')}{field('occasional','withheldRef','Documento da retenção liberatória')}</>}
|
||||
<button type="button" className="rounded border p-2" onClick={()=>save('occasional')}>Calcular e guardar operações ocasionais</button></section>}
|
||||
{(above||acq.result)&&<section className="space-y-3 rounded border p-4"><h4>Aquisições acima do limite global</h4><p>Reutiliza a aquisição, os seus documentos e o acumulado global guardados acima. A parcela excedente não recebe automaticamente a taxa de 5% nem a taxa de 20% do excesso de vendas ISPC.</p>{select('acquisitions','route','Tratamento próprio da parcela excedente',[['unknown','Por identificar—mostrar parcelas sem total presumido'],['ispc_supplier','Fornecedor com opção ISPC aplicável'],['irps_isolated','Acto isolado sujeito a IRPS57(2)k']])}{acq.input.route==='ispc_supplier'&&field('acquisitions','supplierOptionRef','Referência da opção/registo do fornecedor e operações abrangidas')}{acq.input.route==='irps_isolated'&&<>{yesno('acquisitions','noIspcOnExcess','Sem opção ISPC aplicável a esta parcela, segundo documento indicado')}{yesno('acquisitions','isolatedAct','Acto isolado qualificado pelo artigo8(3h,4)doIRPS')}{yesno('acquisitions','incomeInMoz','Rendimento obtido em Moçambique')}{field('acquisitions','grossExcess','Rendimento ilíquido da parcela excedente em MZN—sem dedução de custos ou IVA')}{field('acquisitions','grossRef','Suporte da base ilíquida')}{field('acquisitions','reference','Suporte da classificação IRPS desta parcela')}</>}<button type="button" className="rounded border p-2" onClick={()=>save('acquisitions')}>Calcular e guardar parcela excedente</button></section>}
|
||||
<section className="space-y-3 rounded border p-4"><h4>Formalidades de2026—preparação do B–Geral</h4><p>O Comunicado AT9/2026indica o B–Geral durante a adaptação do sistema, com pagamentos em Janeiro, Abril, Julho e Outubro. O Modelo30disponível conserva campos antigos; não os aplicamos a2026. Esta preparação não submete nem paga à AT.</p>{select('formalities','sourceKind','Cálculo a preparar',[['quarter','Trimestral habitual'],['occasional','Operações ocasionais próprias'],['acquisitions','Retenção da parcela excedente qualificada']])}{formal.input.sourceKind==='acquisitions'&&field('formalities','retentionFormRef','Modelo/código e instrução para entrega das retenções ISPC/IRPS, separados do imposto próprio')}{field('formalities','name','Nome/designação social—quadro5')}{field('formalities','nuit','NUIT—quadro3')}{field('formalities','fiscalArea','Área Fiscal/UGC—quadro3')}{field('formalities','address','Domicílio fiscal—quadro6')}{select('formalities','declaration','Tipo de declaração—quadro1',[['initial','Inicial'],['substitution','Substituição']])}{field('formalities','formMonth','Mês a inscrever no quadro2—não presumido pelo mês de pagamento')}{field('formalities','formYear','Ano a inscrever no quadro2')}{field('formalities','formPeriodRef','Instrução/correspondência usada para o período do quadro2')}{select('formalities','interestSituation','Juros compensatórios—quadro10',[['','Por esclarecer'],['none','Sem juros, segundo suporte indicado'],['amount','Montante documentado']])}{formal.input.interestSituation==='amount'&&field('formalities','interestAmount','Montante de juros documentado')}{field('formalities','interestRef','Suporte da situação dos juros')}{select('formalities','externalStatus','Histórico externo declarado',[['preparation','Em preparação'],['submitted','Submetido'],['received','Recebido pela AT'],['paid','Pagamento efectuado']])}{formal.input.externalStatus!=='preparation'&&<>{field('formalities','externalRef','Referência externa')}{field('formalities','externalDate','Data do acto externo','date')}</>}
|
||||
<button type="button" className="rounded border p-2" onClick={()=>save('formalities')}>Preparar e guardar campos B–Geral</button><button type="button" className="rounded border p-2" onClick={()=>{try{const html=ispcFormalPreparationHtml(draft),url=URL.createObjectURL(new Blob([html],{type:'text/html;charset=utf-8'})),a=document.createElement('a');a.href=url;a.download='ISPC-preparacao-B-Geral.html';a.click();URL.revokeObjectURL(url);setError('');}catch(err){setError(String(err));}}}>Descarregar preparação B–Geral</button></section>
|
||||
{ispcResidualReportRows(draft).map((r,n)=><p key={n}><strong>{r[1]}:</strong> {r[2]}<small className="block">{r[3]}</small></p>)}
|
||||
</section>;
|
||||
}catch(err){return<p role="alert">{String(err)}</p>;}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import {ispcEligibilityBook} from '@/lib/ispc-eligibility';
|
||||
import {ispcWithholdingBook,saveIspcWithholdingBook,recordIspcWithholding,ispcWithholdingReportRows,type IspcWithholdingInput} from '@/lib/ispc-withholding';
|
||||
export function SimulationIspcWithholding({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
||||
if(draft.fiscal_component!=='ispc')return null;
|
||||
try{if(ispcEligibilityBook(draft).input.mode==='occasional')return<p>Retenções do adquirente:entradas preservadas. Neste percurso de vendedor ocasional,registe a retenção recebida no quadro próprio abaixo.</p>;}catch{/* Existing recovery error stays explicit. */}
|
||||
try{const b=ispcWithholdingBook(draft),i=b.input,change=(p:Partial<IspcWithholdingInput>)=>onChange('modelo_a_snapshot',saveIspcWithholdingBook(draft,{...b,input:{...i,...p}}));return<section aria-label="Retenções ISPC" className="space-y-3 rounded border p-4"><h4>ISPC — retenção em aquisições ocasionais</h4><label className="block">Existem aquisições abrangidas pelo artigo 12(3–4)?<select value={i.applicable} onChange={e=>change({applicable:e.target.value as IspcWithholdingInput['applicable']})}><option value="">Por esclarecer</option><option value="no">Não</option><option value="yes">Sim — conferir condições</option></select></label>{i.applicable==='yes'&&<><p>Registe apenas aquisições do mesmo trimestre. O acumulado anterior cobre todas as aquisições desta via no ano e evita reutilizar o limite por fornecedor ou oportunidade.</p>{(['quarter','base','priorAnnualPurchases','reference'] as const).map(k=><label className="block" key={k}>{{quarter:'Trimestre de 2026',base:'Base de aquisições deste trimestre em MZN',priorAnnualPurchases:'Aquisições globais anteriores de 2026 em MZN',reference:'Suporte das aquisições e condições'}[k]}<input className="block rounded border p-2" value={i[k]} onChange={e=>change({[k]:e.target.value})}/></label>)}{(['naturalOccasional','unregistered','related']as const).map(k=><label className="block" key={k}>{{naturalOccasional:'Fornecedor pessoa singular ocasional abrangido por 3(3–4)',unregistered:'Fornecedor não inscrito para tributação',related:'Bens relacionados com a actividade do adquirente'}[k]}<select value={i[k]} onChange={e=>change({[k]:e.target.value})}><option value="">Por esclarecer</option><option value="yes">Sim</option><option value="no">Não</option></select></label>)}<label className="block">Actividade da operação ocasional<select value={i.activity} onChange={e=>change({activity:e.target.value as IspcWithholdingInput['activity']})}>{[['','Por identificar'],['forestry','Silvícola'],['fishery','Pesqueira'],['livestock','Pecuária'],['agriculture','Agrícola'],['poultry','Avícola'],['beekeeping','Apícola'],['other','Outra']].map(([v,l])=><option key={v} value={v}>{l}</option>)}</select></label></>}<button type="button" className="rounded border p-2" onClick={()=>onChange('modelo_a_snapshot',saveIspcWithholdingBook(draft,recordIspcWithholding(draft,b)))}>Conferir e guardar retenção ISPC</button>{ispcWithholdingReportRows(draft).map((r,n)=><p key={n}><strong>{r[1]}:</strong> {r[2]}<small className="block">{r[3]}</small></p>)}</section>;}catch(e){return<p role="alert">{String(e)}</p>;}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import {acquisitionScope} from './iva-acquisitions.ts';
|
||||
import {decimalFraction,fractionPresentation,type FiscalFraction} from './fiscal-rational.ts';
|
||||
|
||||
export const ispcEligibilitySource='L4-A:Lei9/2025,BR248/1.ºsuplemento,republicaçãoISPC,arts2–5,9-A/13;PDF10–11/p2180(10–11);vigência2026art6/PDF9. Enquadramento preliminar de actividade habitual;opção separada;sem liquidação trimestral,retenção,submissão ou alteração de IVA/IRPC/IRPS.';
|
||||
export const ispcActivities=[['forestry','Silvícola'],['fishery','Pesqueira'],['livestock','Pecuária'],['agriculture','Agrícola'],['poultry','Avícola'],['beekeeping','Apícola'],['industry','Industrial'],['commerce','Comercial'],['craft','Artesanato'],['services12','Serviços do artigo8(1)b'],['liberal15','Profissão liberal do artigo8(1)c'],['other','Outra actividade,fora dos âmbitos identificados']] as const;
|
||||
export type IspcActivity=typeof ispcActivities[number][0];
|
||||
type Choice=''|'yes'|'no';
|
||||
export type IspcEligibilityInput={entityRef:string;personType:''|'singular'|'collective';origin:'projected'|'effective';assessmentDate:string;currency:string;mode:'regular'|'occasional';activities:IspcActivity[];activityDescription:string;territory:Choice;establishments:string;basis:''|'previous_year'|'start_forecast';referenceYear:string;annualReference:string;annualReferenceRef:string;forecastConfirmed:Choice;forecastConfirmationRef:string;organizedRequired:Choice;sharesInIspc:Choice;sharesAnonymous:Choice;otherActivities:Choice;unlistedServices:Choice;liberalDaysSameEntity:string;liberalClientRef:string;generalRegimeChosen:Choice;generalThreeYearsCompleted:Choice;generalRegimeRef:string;option:'preparation'|'opted'|'not_opted';optionReference:string;optionDate:string};
|
||||
export type IspcEligibilityResult={calculatedAt:string;key:string;scope:string;input:IspcEligibilityInput;status:'compatible'|'incompatible'|'indeterminate';reason:string;missing:string[];annualReference:FiscalFraction|null;optionStatus:'preparation'|'recorded'|'not_opted'|'indeterminate';optionReason:string;source:string};
|
||||
export type IspcEligibilityBook={version:1;input:IspcEligibilityInput;result?:IspcEligibilityResult;history?:IspcEligibilityResult[]};
|
||||
const scope=(d:Record<string,unknown>)=>acquisitionScope(d);
|
||||
export function ispcReuseValues(d:Record<string,unknown>):Partial<IspcEligibilityInput>{
|
||||
const p:Partial<IspcEligibilityInput>={},person=String(d.person_type??'');if(['singular','sole_trader'].includes(person))p.personType='singular';else if(person==='collective')p.personType='collective';
|
||||
if(typeof d.fiscal_activity==='string'&&d.fiscal_activity.trim())p.activityDescription=d.fiscal_activity;
|
||||
const establishments=String(d.fiscal_establishments??'');if(/^[1-9]\d{0,4}$/.test(establishments))p.establishments=establishments;
|
||||
const entity=String(d.fiscal_entity_ref||d.organization_name||'');if(entity.trim())p.entityRef=entity;
|
||||
return p;
|
||||
}
|
||||
export function newIspcEligibilityInput(d:Record<string,unknown>):IspcEligibilityInput{return{entityRef:'',personType:'',origin:'projected',assessmentDate:'2026-01-01',currency:d.currency==='MZN'?'MZN':'',mode:'regular',activities:[],activityDescription:'',territory:'',establishments:'',basis:'',referenceYear:'',annualReference:'',annualReferenceRef:'',forecastConfirmed:'',forecastConfirmationRef:'',organizedRequired:'',sharesInIspc:'',sharesAnonymous:'',otherActivities:'',unlistedServices:'',liberalDaysSameEntity:'',liberalClientRef:'',generalRegimeChosen:'',generalThreeYearsCompleted:'',generalRegimeRef:'',option:'preparation',optionReference:'',optionDate:'',...ispcReuseValues(d)};}
|
||||
function store(d:Record<string,unknown>):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 não recuperáveis;originais preservados.');return s;}
|
||||
function map(d:Record<string,unknown>):Record<string,IspcEligibilityBook>{const value=store(d).ispcEligibility;if(value===undefined)return{};if(!value||typeof value!=='object'||Array.isArray(value))throw Error('PreparaçãoISPC não recuperável;originais preservados.');return value as Record<string,IspcEligibilityBook>;}
|
||||
function validate(b:IspcEligibilityBook):void{
|
||||
const sample=newIspcEligibilityInput({});if(!b||b.version!==1||!b.input||typeof b.input!=='object'||Object.keys(sample).some(k=>k==='activities'?!Array.isArray(b.input.activities)||new Set(b.input.activities).size!==b.input.activities.length||b.input.activities.some(a=>!ispcActivities.some(([kind])=>kind===a)):typeof b.input[k as keyof IspcEligibilityInput]!=='string')||!['','singular','collective'].includes(b.input.personType)||!['projected','effective'].includes(b.input.origin)||!['regular','occasional'].includes(b.input.mode)||!['','previous_year','start_forecast'].includes(b.input.basis)||!['preparation','opted','not_opted'].includes(b.input.option)||['territory','forecastConfirmed','organizedRequired','sharesInIspc','sharesAnonymous','otherActivities','unlistedServices','generalRegimeChosen','generalThreeYearsCompleted'].some(k=>!['','yes','no'].includes(String(b.input[k as keyof IspcEligibilityInput])))||b.history!==undefined&&!Array.isArray(b.history)||b.result!==undefined&&(!b.result.input||!Array.isArray(b.result.missing)||!['compatible','incompatible','indeterminate'].includes(b.result.status)))throw Error('EntradasISPC não recuperáveis;sem substituir por valores vazios.');
|
||||
}
|
||||
export function ispcEligibilityBook(d:Record<string,unknown>):IspcEligibilityBook{const b=map(d)[scope(d)]??{version:1,input:newIspcEligibilityInput(d)};validate(b);return b;}
|
||||
export function saveIspcEligibilityBook(d:Record<string,unknown>,b:IspcEligibilityBook):string{validate(b);return JSON.stringify({...store(d),ispcEligibility:{...map(d),[scope(d)]:b}});}
|
||||
const validDate=(v:string)=>/^20\d{2}-(0[1-9]|1[0-2])-\d{2}$/.test(v)&&!Number.isNaN(Date.parse(v))&&new Date(v).toISOString().slice(0,10)===v;
|
||||
function option(i:IspcEligibilityInput):Pick<IspcEligibilityResult,'optionStatus'|'optionReason'>{
|
||||
if(i.option==='not_opted')return{optionStatus:'not_opted',optionReason:'Sem opçãoISPC declarada;não aplicar a exclusão de outros impostos doart5.'};
|
||||
if(i.option==='preparation')return{optionStatus:'preparation',optionReason:'Opção em preparação;compatibilidade de acesso não é adesão nem alteração automática de regime.'};
|
||||
if(!i.optionReference.trim()||!validDate(i.optionDate)||!validDate(i.assessmentDate)||i.optionDate>i.assessmentDate)return{optionStatus:'indeterminate',optionReason:'Identifique referência e data da opção,até à data de avaliação;não inferir adesão pela selecçãoISPC.'};
|
||||
return{optionStatus:'recorded',optionReason:'Opção registada segundo documento ou pressuposto declarado;sem submissãoAT ou reescrita dos livros deIVA/IRPC/IRPS.'};
|
||||
}
|
||||
function assess(i:IspcEligibilityInput):Pick<IspcEligibilityResult,'status'|'reason'|'missing'|'annualReference'>{
|
||||
let annual:FiscalFraction|null=null;try{annual=decimalFraction(i.annualReference);}catch{ /* Missing or invalid is never zero. */ }
|
||||
const stop=(status:IspcEligibilityResult['status'],reason:string,missing:string[]=[])=>({status,reason,missing,annualReference:annual});
|
||||
if(!validDate(i.assessmentDate)||!i.assessmentDate.startsWith('2026-')||i.currency!=='MZN')return stop('indeterminate','Este incremento cobre apenas avaliação2026emMZN;identifique data e moeda sem conversão silenciosa.',['data2026','moedaMZN']);
|
||||
if(i.mode==='occasional')return stop('indeterminate','Operação ocasional3(3–4):conservar dados;use o percurso específico de operações ocasionais próprias abaixo,com incidênciaIRPS e famílias3(4).',['enquadramento específico da operação ocasional']);
|
||||
if(i.territory==='no')return stop('incompatible','O âmbito territorial declarado não corresponde ao exercício em território nacional de2(1);nacionalidade do investidor não substitui este facto.');
|
||||
if(i.activities.includes('other')||i.otherActivities==='yes')return stop('incompatible','Actividade fora dos âmbitos2/3declarada;exclusão3(2)c,não aplicarISPC por nome do sector.');
|
||||
if(i.organizedRequired==='yes')return stop('incompatible','Obrigação de contabilidade organizada declarada:4(1)b não permite este enquadramento. Manter contabilidade voluntária distinto de obrigação.');
|
||||
if(i.sharesInIspc==='yes'||i.sharesAnonymous==='yes')return stop('incompatible','Participações abrangidas por3(2)a/b declaradas;enquadramentoISPC incompatível.');
|
||||
if(/^[1-9]\d{0,4}$/.test(i.establishments)&&Number(i.establishments)>1)return stop('incompatible','Actividade distribuída por vários estabelecimentos:exclusão3(2)d;sem presumir um estabelecimento por oportunidade.');
|
||||
const service=i.activities.some(a=>['services12','liberal15'].includes(a)),liberal=i.activities.includes('liberal15');
|
||||
if(service&&i.unlistedServices==='yes')return stop('incompatible','Serviços fora dos previstos declarados:exclusão3(2)f. Categoria e natureza próprias devem ser identificadas.');
|
||||
if(liberal&&/^\d{1,3}$/.test(i.liberalDaysSameEntity)&&Number(i.liberalDaysSameEntity)<=366&&Number(i.liberalDaysSameEntity)>183)return stop('incompatible','Serviços8(1)càmesma entidade por mais183dias durante o ano:exclusão3(2)e. Não estender esta condição automaticamente aos serviços8(1)b.');
|
||||
if(i.generalRegimeChosen==='yes'&&i.generalThreeYearsCompleted==='no')return stop('incompatible','Permanência mínima de três anos nos impostos gerais5(3)ainda não cumprida,segundo factos declarados.');
|
||||
if(annual&&(i.basis==='previous_year'&&i.referenceYear==='2025'||i.basis==='start_forecast'&&i.referenceYear==='2026')&&BigInt(annual.numerator)>4000000n*BigInt(annual.denominator))return stop('incompatible','Volume anual de referência superior4.000.000MZN:fora do acesso4(1)a/4(2). Excesso do próprio ano e20%de8(1)d têm tratamento separado;não liquidado aqui.');
|
||||
const missing:string[]=[];if(!i.personType)missing.push('pessoa singular ou colectiva');if(i.territory!=='yes')missing.push('exercício em território nacional');if(!i.activities.length||!i.activityDescription.trim())missing.push('actividade/natureza identificadas');if(!/^[1-9]\d{0,4}$/.test(i.establishments))missing.push('número de estabelecimentos');
|
||||
for(const[field,label]of [['organizedRequired','obrigação de contabilidade organizada'],['sharesInIspc','participações noutras sociedadesISPC'],['sharesAnonymous','participaçõesSA/sócios não identificáveis'],['otherActivities','actividades fora do âmbito'],['generalRegimeChosen','opção pelos impostos gerais']] as const)if(i[field]==='')missing.push(label);
|
||||
if(!i.basis)missing.push('origem do volume anual de referência');if(!annual)missing.push('montante anual de referência');const expected=i.basis==='previous_year'?'2025':i.basis==='start_forecast'?'2026':'';if(expected&&i.referenceYear!==expected)missing.push(`ano${expected}da referência;não reinterpretar outro ano`);
|
||||
if(i.basis==='start_forecast'&&(i.forecastConfirmed!=='yes'||i.origin==='effective'&&!i.forecastConfirmationRef.trim()))missing.push('previsão da declaração de início confirmadaAT4(2),ou pressuposto expresso na projecção');
|
||||
if(service&&i.unlistedServices==='')missing.push('correspondência dos serviços aos âmbitos daLei');
|
||||
if(liberal&&(!/^\d{1,3}$/.test(i.liberalDaysSameEntity)||Number(i.liberalDaysSameEntity)>366||!i.liberalClientRef.trim()))missing.push('maior duração anual por mesma entidade e suporte declarado');
|
||||
if(i.generalRegimeChosen==='yes'&&(i.generalThreeYearsCompleted!=='yes'||!i.generalRegimeRef.trim()))missing.push('cumprimento dos três anos5(3)e referência da opção/registo');
|
||||
if(missing.length)return stop('indeterminate','Condições específicas por esclarecer;desconhecido não significa não aplicável nemzero.',missing);
|
||||
return stop('compatible','Condições de acesso da actividade habitual compatíveis com os dados de referência declarados;opção separada. Volume do ano em curso, trimestre, excesso e mínimo têm apuramento trimestral próprio; retenções têm registo separado.'+(liberal?' Serviçosliberais:limite5anos9-A,contagemtransitória13a partir da vigência2026;sem presumir permanência fora da cobertura.':''));
|
||||
}
|
||||
const key=(d:Record<string,unknown>,b:IspcEligibilityBook)=>JSON.stringify(['ispc-eligibility/1',scope(d),b.input]);
|
||||
export function ispcEligibilityCurrent(d:Record<string,unknown>,b:IspcEligibilityBook):boolean{return!!b.result&&b.result.key===key(d,b);}
|
||||
export function recordIspcEligibility(d:Record<string,unknown>,b:IspcEligibilityBook,now=new Date().toISOString()):IspcEligibilityBook{validate(b);const result:IspcEligibilityResult={calculatedAt:now,key:key(d,b),scope:scope(d),input:structuredClone(b.input),...assess(b.input),...option(b.input),source:ispcEligibilitySource};return{...b,...(b.result?{history:[...(b.history??[]),structuredClone(b.result)]}:{}),result};}
|
||||
export function ispcReuseDiff(d:Record<string,unknown>,b:IspcEligibilityBook):Array<{field:keyof IspcEligibilityInput;before:string;after:string}>{return Object.entries(ispcReuseValues(d)).filter(([field,value])=>b.input[field as keyof IspcEligibilityInput]!==value).map(([field,value])=>({field:field as keyof IspcEligibilityInput,before:String(b.input[field as keyof IspcEligibilityInput]),after:String(value)}));}
|
||||
export function ispcEligibilityReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=ispcEligibilityBook(d),r=b.result;if(!r)return[];const i=r.input;return[['ISPC','L4-A — enquadramento2026',`${r.status==='compatible'?'Compatível com os dados de referência':r.status==='incompatible'?'Incompatível':'Indeterminado'};${r.reason};falta:${r.missing.join('; ')||'nenhum dado deste recorte'}`,`${r.scope};${ispcEligibilityCurrent(d,b)?'Entradas correspondentes':'Histórico preservado;rever entradas'};${r.calculatedAt};${r.source}`],['ISPC','Origem e âmbito',`${i.entityRef||'Entidade por identificar'};${i.personType};${i.origin==='projected'?'Pressupostos de simulação':'Dados efectivos declarados'};${i.activities.map(a=>ispcActivities.find(([kind])=>kind===a)?.[1]??a).join('; ')};${i.activityDescription};estabelecimentos${i.establishments};territórionacional${i.territory}`,`Referênciaanual:${i.basis}/${i.referenceYear};${r.annualReference?fractionPresentation(r.annualReference).decimal:'Indeterminado'}MZN;${i.annualReferenceRef};previsãoAT${i.forecastConfirmed}/${i.forecastConfirmationRef};liberal${i.liberalDaysSameEntity}dias/${i.liberalClientRef};factos:${JSON.stringify({organizedRequired:i.organizedRequired,sharesInIspc:i.sharesInIspc,sharesAnonymous:i.sharesAnonymous,otherActivities:i.otherActivities,unlistedServices:i.unlistedServices,generalRegimeChosen:i.generalRegimeChosen,generalThreeYearsCompleted:i.generalThreeYearsCompleted,generalRegimeRef:i.generalRegimeRef})}`],['ISPC','Opção e próximo passo',`${r.optionReason};referência${i.optionReference};data${i.optionDate}`,`Prossiga no apuramento trimestral; esta avaliação não adopta regime nem calcula imposto. ${r.source}`]];}catch(error){return[['ISPC','Enquadramento','Dados não recuperáveis;originais preservados',String(error)]];}}
|
||||
@@ -0,0 +1,45 @@
|
||||
import {acquisitionScope} from './iva-acquisitions.ts';
|
||||
import {ispcEligibilityBook,ispcEligibilityCurrent,type IspcEligibilityResult} from './ispc-eligibility.ts';
|
||||
import {addFractions,decimalFraction,fraction,fractionPresentation,subtractFractions,type FiscalFraction} from './fiscal-rational.ts';
|
||||
export const ispcQuarterSource='Lei 9/2025, republicação ISPC, arts 8, 9, 10, 10-A e 11; BR248/2025, PDF11/p2180(11). Taxa do escalão anual aplicada à base trimestral (8(1)a e 9); 20% apenas na parcela em excesso de 4.000.000; actividades cumuladas: taxa mais alta (8(2)). Sem fraccionar os limites anuais por quatro nem copiar o volume do ano anterior. Preparação do apuramento; sem submissão ou pagamento AT.';
|
||||
export type IspcQuarterInput={year:string;quarter:string;sales:[string,string,string,string];salesRefs:[string,string,string,string];annualBandVolume:string;annualBandOrigin:''|'forecast'|'closed_year';annualBandRef:string;coverage:''|'all_taxpayer_activity';};
|
||||
export type IspcQuarterResult={key:string;calculatedAt:string;scope:string;input:IspcQuarterInput;eligibility:IspcEligibilityResult|null;status:'calculated'|'indeterminate'|'not_applicable';reason:string;missing:string[];base:FiscalFraction|null;prior:FiscalFraction|null;ordinary:FiscalFraction|null;excess:FiscalFraction|null;rate:number|null;tax:FiscalFraction|null;payment:FiscalFraction|null;declaration:boolean;projected:boolean;source:string};
|
||||
export type IspcQuarterBook={version:1;input:IspcQuarterInput;result?:IspcQuarterResult;history?:IspcQuarterResult[]};
|
||||
export const newIspcQuarterInput=():IspcQuarterInput=>({year:'2026',quarter:'1',sales:['','','',''],salesRefs:['','','',''],annualBandVolume:'',annualBandOrigin:'',annualBandRef:'',coverage:''});
|
||||
function snapshot(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 não recuperáveis; originais preservados.');return s;}
|
||||
function validate(b:IspcQuarterBook){if(!b||b.version!==1||!b.input||['year','quarter','annualBandVolume','annualBandOrigin','annualBandRef','coverage'].some(k=>typeof b.input[k as keyof IspcQuarterInput]!=='string')||!['','forecast','closed_year'].includes(b.input.annualBandOrigin)||!['','all_taxpayer_activity'].includes(b.input.coverage)||!Array.isArray(b.input.sales)||b.input.sales.length!==4||b.input.sales.some(v=>typeof v!=='string')||!Array.isArray(b.input.salesRefs)||b.input.salesRefs.length!==4||b.input.salesRefs.some(v=>typeof v!=='string')||b.history!==undefined&&!Array.isArray(b.history)||b.result!==undefined&&(!b.result.input||!Array.isArray(b.result.missing)))throw Error('Apuramento ISPC não recuperável; sem substituir por zero ou apagar histórico.');}
|
||||
function books(d:Record<string,unknown>):Record<string,IspcQuarterBook>{const v=snapshot(d).ispcQuarters;if(v===undefined)return{};if(!v||typeof v!=='object'||Array.isArray(v))throw Error('Mapa trimestral ISPC inválido; originais preservados.');return v;}
|
||||
export function ispcQuarterBook(d:Record<string,unknown>):IspcQuarterBook{const b=books(d)[acquisitionScope(d)]??{version:1,input:newIspcQuarterInput()};validate(b);return b;}
|
||||
export function saveIspcQuarterBook(d:Record<string,unknown>,b:IspcQuarterBook):string{validate(b);return JSON.stringify({...snapshot(d),ispcQuarters:{...books(d),[acquisitionScope(d)]:b}});}
|
||||
const cmp=(a:FiscalFraction,b:FiscalFraction)=>BigInt(a.numerator)*BigInt(b.denominator)-BigInt(b.numerator)*BigInt(a.denominator);
|
||||
const minimum=(a:FiscalFraction,b:FiscalFraction)=>cmp(a,b)<=0n?a:b;
|
||||
const positive=(a:FiscalFraction)=>cmp(a,fraction(0n))>0n?a:fraction(0n);
|
||||
const atRate=(v:FiscalFraction,r:number)=>fraction(BigInt(v.numerator)*BigInt(r),BigInt(v.denominator)*100n);
|
||||
function eligibility(d:Record<string,unknown>){const b=ispcEligibilityBook(d);return ispcEligibilityCurrent(d,b)?b.result??null:null;}
|
||||
const key=(d:Record<string,unknown>,b:IspcQuarterBook)=>JSON.stringify(['ispc-quarter/1',acquisitionScope(d),b.input,eligibility(d)]);
|
||||
export const ispcQuarterCurrent=(d:Record<string,unknown>,b:IspcQuarterBook)=>!!b.result&&b.result.key===key(d,b);
|
||||
export function recordIspcQuarter(d:Record<string,unknown>,b:IspcQuarterBook,now=new Date().toISOString()):IspcQuarterBook{
|
||||
validate(b);const i=b.input,e=eligibility(d),r:IspcQuarterResult={key:key(d,b),calculatedAt:now,scope:acquisitionScope(d),input:structuredClone(i),eligibility:e?structuredClone(e):null,status:'indeterminate',reason:'',missing:[],base:null,prior:null,ordinary:null,excess:null,rate:null,tax:null,payment:null,declaration:false,projected:e?.input.origin==='projected'||i.annualBandOrigin==='forecast',source:ispcQuarterSource};
|
||||
const finish=()=>({...b,...(b.result?{history:[...(b.history??[]),structuredClone(b.result)]}:{}),result:r});
|
||||
if(!e){r.missing.push('Avaliação de elegibilidade actual correspondente às entradas');r.reason='Reveja e guarde o enquadramento; a avaliação anterior continua no histórico.';return finish();}
|
||||
if(e.status==='incompatible'||e.optionStatus==='not_opted'){r.status='not_applicable';r.reason='Os factos guardados não permitem aplicar ISPC ou indicam que não optou. Outros regimes mantêm os seus percursos.';return finish();}
|
||||
if(e.status!=='compatible'){r.missing.push(...e.missing);r.reason='Enquadramento indeterminado; não produzir imposto zero.';return finish();}
|
||||
// A preparation scenario may estimate tax, but never asserts an effective election.
|
||||
if(e.optionStatus==='indeterminate'||e.input.origin==='effective'&&e.optionStatus!=='recorded'){r.missing.push('Opção documentada para apuramento efectivo; a preparação permite somente simulação');}
|
||||
if(e.optionStatus==='preparation')r.projected=true;
|
||||
if(i.year!=='2026'||!['1','2','3','4'].includes(i.quarter))r.missing.push('Ano 2026 e trimestre entre 1 e 4');
|
||||
if(i.coverage!=='all_taxpayer_activity')r.missing.push('Confirmar volume de todas as actividades do sujeito passivo, não apenas desta oportunidade');
|
||||
const q=Number(i.quarter),amounts:FiscalFraction[]=[],allFour=i.annualBandOrigin==='closed_year'&&!e.input.activities.some(a=>['liberal15','services12'].includes(a));
|
||||
if(e.input.origin==='effective'&&e.input.optionDate&&['1','2','3','4'].includes(i.quarter)&&e.input.optionDate>`2026-${['03-31','06-30','09-30','12-31'][q-1]}`)r.missing.push('A opção registada é posterior ao trimestre; esclarecer operações abrangidas sem retroagir automaticamente');
|
||||
if(['1','2','3','4'].includes(i.quarter))for(let n=0;n<(allFour?4:q);n++){try{amounts[n]=decimalFraction(i.sales[n]);}catch{r.missing.push(`Volume do trimestre ${n+1}, incluindo zero expresso`);}if(!i.salesRefs[n].trim())r.missing.push(`Suporte ou pressuposto do trimestre ${n+1}`);}
|
||||
const liberal=e.input.activities.includes('liberal15'),service=e.input.activities.includes('services12');
|
||||
let band:FiscalFraction|null=null;
|
||||
if(!liberal&&!service){try{band=decimalFraction(i.annualBandVolume);}catch{r.missing.push('Volume anual de 2026 para identificar o escalão; distinto do volume de acesso 2025');}if(!i.annualBandOrigin||!i.annualBandRef.trim())r.missing.push('Origem (previsão ou ano encerrado) e suporte do escalão anual');}
|
||||
if(r.missing.length){r.reason='Faltam dados específicos para este apuramento; os restantes percursos mantêm-se disponíveis.';return finish();}
|
||||
r.base=amounts[q-1];r.prior=addFractions(amounts.slice(0,q-1));const cumulative=addFractions(amounts.slice(0,q)),annualTotal=addFractions(amounts);
|
||||
if(band&&(cmp(band,cumulative)<0n||i.annualBandOrigin==='closed_year'&&cmp(band,annualTotal)!==0n)){r.reason='Volume anual do escalão diverge dos trimestres declarados; reveja a divergência antes de calcular.';r.missing.push('Reconciliar referência anual 2026 com o acumulado trimestral');return finish();}
|
||||
r.rate=liberal?15:service?12:band&&cmp(band,fraction(1000000n))<=0n?3:band&&cmp(band,fraction(2500000n))<=0n?4:5;
|
||||
r.ordinary=minimum(r.base,positive(subtractFractions(fraction(4000000n),r.prior)));r.excess=subtractFractions(r.base,r.ordinary);r.tax=addFractions([atRate(r.ordinary,r.rate),atRate(r.excess,20)]);r.payment=cmp(r.tax,fraction(500n))<0n?fraction(0n):r.tax;r.declaration=true;r.status='calculated';r.reason=`${r.projected?'Simulação com pressupostos explícitos; sem adesão automática.':'Apuramento segundo factos e opção documentados.'} Taxa ${r.rate}% sobre a parcela ordinária trimestral e 20% apenas sobre o excesso anual. ${cmp(r.tax,fraction(500n))<0n?'Prestação inferior a 500 MZN: sem pagamento; obrigação declarativa preservada.':'Prestação igual ou superior a 500 MZN: montante a preparar para pagamento.'} Sem dedução de custos, retenções sofridas presumidas, compensação ou acumulação de prestações dispensadas.`;return finish();
|
||||
}
|
||||
const amount=(v:FiscalFraction|null)=>v?`${fractionPresentation(v).decimal} MZN (${v.numerator}/${v.denominator})`:'Indeterminado';
|
||||
export function ispcQuarterReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=ispcQuarterBook(d),r=b.result;if(!r)return[];return[['ISPC',`Apuramento ${r.input.year}/T${r.input.quarter}`,`${r.status==='calculated'?'Calculado':r.status==='not_applicable'?'Não aplicável':'Indeterminado'}; ${r.reason}; falta: ${r.missing.join('; ')||'nenhum dado deste recorte'}`,`${r.scope}; ${ispcQuarterCurrent(d,b)?'Entradas correspondentes':'Histórico preservado; rever entradas'}; ${r.calculatedAt}; ${r.source}`],['ISPC','Base e taxa trimestral',`Base: ${amount(r.base)}; anterior no ano: ${amount(r.prior)}; ordinária: ${amount(r.ordinary)} a ${r.rate??'indeterminada'}%; excesso: ${amount(r.excess)} a 20%`,`Volume anual de escalão: ${r.input.annualBandVolume||'não necessário para taxa de serviços'}; ${r.input.annualBandOrigin}; ${r.input.annualBandRef}; suportes: ${r.input.salesRefs.join('; ')}`],['ISPC','Imposto, pagamento e declaração',`Imposto: ${amount(r.tax)}; prestação a pagar: ${amount(r.payment)}; obrigação declarativa: ${r.declaration?'mantida':'por determinar neste percurso'}; ${r.projected?'simulação':'factos efectivos'}`,`Opção: ${r.eligibility?.optionStatus??'indeterminada'}; referência: ${r.eligibility?.input.optionReference??''}; histórico: ${b.history?.length??0} versão(ões) anterior(es). Sem submissão AT.`]];}catch(error){return[['ISPC','Apuramento não recuperável',String(error),'Originais preservados.']];}}
|
||||
@@ -0,0 +1,86 @@
|
||||
import {acquisitionScope} from './iva-acquisitions.ts';
|
||||
import {ispcEligibilityBook,ispcEligibilityCurrent} from './ispc-eligibility.ts';
|
||||
import {ispcWithholdingBook} from './ispc-withholding.ts';
|
||||
import {ispcQuarterBook,ispcQuarterCurrent} from './ispc-quarter.ts';
|
||||
import {addFractions,decimalFraction,fraction,fractionPresentation,subtractFractions,type FiscalFraction} from './fiscal-rational.ts';
|
||||
export type ResidualKind='occasional'|'acquisitions'|'formalities';
|
||||
export type ResidualResult={key:string;scope:string;calculatedAt:string;status:'calculated'|'settled_by_withholding'|'partial'|'indeterminate'|'not_applicable';reason:string;missing:string[];input:Record<string,string>;amounts:Record<string,FiscalFraction|null>;details:Record<string,string>;source:string};
|
||||
export type ResidualBook={version:1;kind:ResidualKind;input:Record<string,string>;result?:ResidualResult;history?:ResidualResult[]};
|
||||
export const residualSources={occasional:'ISPC Lei9/2025 arts3(3–4),4,5,8,9,10-A,12(3);BR248 PDF10–11. IRPS republicação Lei19/2017,BR202/7.ºsuplemento,art8(3h,4),9;PDF4/p2602(128). Lei11/2025 não altera estes artigos. Operação imprevisível/não reiterada, pessoa singular sem actividade habitual e famílias restritas; imposto próprio distinto de retenção liberatória documentada.',acquisitions:'ISPC12(3–4):limite global anual2.500.000MZN para factura por conta/retencão5%. Parcela acima do limite não adquire taxa por ultrapassagem. IRPS57(1,2k,4),republicação19/2017 PDF13/p2602(137),e65(1)naLei11/2025 PDF17:acto isolado qualificado e sem opçãoISPC aplicável,20%sobre rendimento ilíquido declarado; não confundir com20%do excesso de vendasISPC8(1)d.',formalities:'AT Comunicado9/2026,06/10/2026,p1:ModeloB–Geral enquanto se ajusta sistema;pagamentos trimestrais emJaneiro/Abril/Julho/Outubro. AT ModeloBGeral2p:quadros1/2/3/5/6/8/10. Modelo30 disponível contém75.000/3%antigos,não usado para calcular2026. Sem submissãoAT automática.'};
|
||||
const blank=(kind:ResidualKind):Record<string,string>=>kind==='occasional'?{personType:'',currency:'',origin:'projected',operationDate:'',quarter:'',noHabitual:'',territory:'',sporadic:'',activity:'',reference:'',amount:'',allQuarterOperations:'',priorYearTurnover:'',priorYearRef:'',organizedRequired:'',option:'preparation',optionRef:'',optionDate:'',settlement:'',annual2026:'',annualOrigin:'',annualRef:'',priorInYear:'',buyerIspc:'',unregistered:'',buyerAnnualPurchases:'',withheldActual:'',withheldRef:''}:kind==='acquisitions'?{route:'unknown',noIspcOnExcess:'',isolatedAct:'',incomeInMoz:'',grossExcess:'',grossRef:'',supplierOptionRef:'',reference:''}:{sourceKind:'quarter',name:'',nuit:'',fiscalArea:'',address:'',declaration:'initial',formMonth:'',formYear:'2026',formPeriodRef:'',interestSituation:'',interestAmount:'',interestRef:'',externalStatus:'preparation',externalRef:'',externalDate:''};
|
||||
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 não recuperáveis; originais preservados.');return s;}
|
||||
function maps(d:Record<string,unknown>):Record<string,Record<string,ResidualBook>>{const v=store(d).ispcResiduals;if(v===undefined)return{};if(!v||typeof v!=='object'||Array.isArray(v))throw Error('Mapa residualISPC inválido; originais preservados.');return v;}
|
||||
function validate(b:ResidualBook,kind:ResidualKind){
|
||||
const enums:Record<string,string[]>=kind==='occasional'?{personType:['','singular','collective'],origin:['projected','effective'],noHabitual:['','yes','no'],territory:['','yes','no'],sporadic:['','yes','no'],activity:['','forestry','fishery','livestock','agriculture','poultry','beekeeping','other'],allQuarterOperations:['','yes','no'],organizedRequired:['','yes','no'],option:['preparation','opted','not_opted'],settlement:['','self','withheld'],annualOrigin:['','forecast','closed_year'],buyerIspc:['','yes','no'],unregistered:['','yes','no']}:kind==='acquisitions'?{route:['unknown','ispc_supplier','irps_isolated'],noIspcOnExcess:['','yes','no'],isolatedAct:['','yes','no'],incomeInMoz:['','yes','no']}:{sourceKind:['quarter','occasional','acquisitions'],declaration:['initial','substitution'],interestSituation:['','none','amount'],externalStatus:['preparation','submitted','received','paid']};
|
||||
if(b?.input&&Object.entries(enums).some(([k,v])=>!v.includes(b.input[k])))throw Error('Opções residuais não recuperáveis;entradas preservadas.');
|
||||
if(!b||b.version!==1||b.kind!==kind||!b.input||Object.keys(blank(kind)).some(k=>typeof b.input[k]!=='string')||b.history!==undefined&&!Array.isArray(b.history)||b.result!==undefined&&(!b.result.input||!b.result.amounts||!Array.isArray(b.result.missing)))throw Error('Livro residualISPC não recuperável; sem substituir por vazio.');}
|
||||
export function ispcResidualBook(d:Record<string,unknown>,kind:ResidualKind):ResidualBook{const m=maps(d)[acquisitionScope(d)];if(m!==undefined&&(!m||typeof m!=='object'||Array.isArray(m)))throw Error('Contexto residual inválido.');let b=m?.[kind];if(!b){const input=blank(kind);if(kind==='occasional'){const i=ispcEligibilityBook(d).input;Object.assign(input,{personType:i.personType,currency:i.currency,origin:i.origin,operationDate:i.assessmentDate,territory:i.territory,option:i.option,optionRef:i.optionReference,optionDate:i.optionDate});}if(kind==='formalities'){if(ispcEligibilityBook(d).input.mode==='occasional'&&m?.occasional?.result)input.sourceKind='occasional';else if(!ispcQuarterBook(d).result&&m?.acquisitions?.result)input.sourceKind='acquisitions';Object.assign(input,{name:String(d.legal_name??d.organization_name??''),nuit:String(d.nuit??''),address:String(d.address??'')});}b={version:1,kind,input};}validate(b,kind);return b;}
|
||||
export function saveIspcResidualBook(d:Record<string,unknown>,b:ResidualBook):string{validate(b,b.kind);const scope=acquisitionScope(d);return JSON.stringify({...store(d),ispcResiduals:{...maps(d),[scope]:{...maps(d)[scope],[b.kind]:b}}});}
|
||||
const cmp=(a:FiscalFraction,b:FiscalFraction)=>BigInt(a.numerator)*BigInt(b.denominator)-BigInt(b.numerator)*BigInt(a.denominator);
|
||||
const rate=(a:FiscalFraction,n:number)=>fraction(BigInt(a.numerator)*BigInt(n),BigInt(a.denominator)*100n);
|
||||
const min=(a:FiscalFraction,b:FiscalFraction)=>cmp(a,b)<0n?a:b;
|
||||
const positive=(a:FiscalFraction)=>cmp(a,fraction(0n))>0n?a:fraction(0n);
|
||||
const validDate=(s:string)=>/^2026-\d{2}-\d{2}$/.test(s)&&!Number.isNaN(Date.parse(s))&&new Date(s).toISOString().slice(0,10)===s;
|
||||
const amount=(s:string,label:string,r:ResidualResult)=>{try{return decimalFraction(s);}catch{r.missing.push(label);return null;}};
|
||||
function dependency(d:Record<string,unknown>,kind:ResidualKind,i:Record<string,string>):unknown{if(kind==='acquisitions'){const e=ispcEligibilityBook(d);return[ispcWithholdingBook(d).input,e.input,e.result?.key];}if(kind==='formalities'){if(i.sourceKind==='quarter'){const b=ispcQuarterBook(d);return[b.input,b.result?.key,ispcQuarterCurrent(d,b)];}const b=ispcResidualBook(d,i.sourceKind==='occasional'?'occasional':'acquisitions');return[b.input,b.result?.key,b.result?.calculatedAt,ispcResidualCurrent(d,b)];}return null;}
|
||||
const key=(d:Record<string,unknown>,b:ResidualBook)=>JSON.stringify(['ispc-residual/1',acquisitionScope(d),b.kind,b.input,dependency(d,b.kind,b.input)]);
|
||||
export const ispcResidualCurrent=(d:Record<string,unknown>,b:ResidualBook)=>!!b.result&&b.result.key===key(d,b);
|
||||
function occasional(i:Record<string,string>,r:ResidualResult){
|
||||
if(i.personType==='collective'||i.noHabitual==='no'||i.territory==='no'||i.sporadic==='no'||i.activity==='other'){r.status='not_applicable';r.reason='Os factos excluem o recorte ocasional3(3–4); conserve o percurso habitual ou o imposto próprio aplicável, sem presumir isenção.';return;}
|
||||
if(i.territory!=='yes')r.missing.push('Operação em território nacional,sem inferir da moeda ou nacionalidade');
|
||||
if(!i.personType)r.missing.push('Pessoa singular por identificar');
|
||||
if(i.currency!=='MZN'||!validDate(i.operationDate)||!['1','2','3','4'].includes(i.quarter)||validDate(i.operationDate)&&Math.ceil(Number(i.operationDate.slice(5,7))/3)!==Number(i.quarter))r.missing.push('Data/trimestre de2026 coerentes e moedaMZN');
|
||||
if(i.noHabitual!=='yes'||i.sporadic!=='yes'||!['forestry','fishery','livestock','agriculture','poultry','beekeeping'].includes(i.activity)||!i.reference.trim())r.missing.push('Pessoa sem actividade habitual,acto imprevisível/não reiterado,família3(4)e suporte da operação');
|
||||
const base=amount(i.amount,'Volume das operações ocasionais deste trimestre, incluindo zero expresso',r);r.amounts.base=base;
|
||||
r.details.IRPS='Acto isolado8(3h)referente a8(2a),não previsível/reiterado8(4);família3(4)ISPC. Não se infere pelo nome do sector.';
|
||||
if(i.settlement==='withheld'){
|
||||
const purchases=amount(i.buyerAnnualPurchases,'Aquisições globais anuais do adquirente, incluindo estas operações',r),actual=amount(i.withheldActual,'Montante efectivamente retido',r);
|
||||
if(i.buyerIspc!=='yes'||i.unregistered!=='yes'||!i.withheldRef.trim())r.missing.push('AdquirenteISPC,fornecedor não inscrito e documento de retenção liberatória12(3)');
|
||||
if(purchases&&base&&(cmp(purchases,base)<0n||cmp(purchases,fraction(2500000n))>0n))r.missing.push('Reconciliar aquisições globais do adquirente dentro do limite2.500.000;fora dele usar tratamento próprio');
|
||||
if(!r.missing.length&&base&&actual){r.amounts.tax=rate(base,5);r.amounts.withheld=actual;if(cmp(actual,r.amounts.tax)!==0n){r.missing.push('Retenção documentada diverge de5%da base;reconciliar diferença sem presumir quitação');return;}r.status='settled_by_withholding';r.details.rate='5';r.reason='Retenção liberatória documentada para estas operações; não somar nova liquidação própria3/4/5%nem usar a retenção como crédito duplicado. Pagamento próprio adicional não é gerado.';}return;
|
||||
}
|
||||
if(i.settlement!=='self'){r.missing.push('Via de liquidação própria ou retenção liberatória documentada');return;}
|
||||
if(i.organizedRequired==='yes'){r.status='not_applicable';r.reason='Obrigação de contabilidade organizada declarada:fora da liquidação própriaISPC4(1b);entradas e documentos conservados,sem presumir isenção noutro imposto.';return;}
|
||||
if(i.allQuarterOperations!=='yes')r.missing.push('Volume de todas as operações ocasionais do sujeito passivo no trimestre');
|
||||
const access=amount(i.priorYearTurnover,'Volume de referência2025, sem inferir zero por ausência de actividade habitual',r);if(!i.priorYearRef.trim()||i.organizedRequired!=='no')r.missing.push('Suporte da referência anual e inexistência de obrigação de contabilidade organizada4(1)');if(access&&cmp(access,fraction(4000000n))>0n){r.status='not_applicable';r.reason='Volume de acesso4(1)superior4.000.000MZN declarado:fora da liquidação própriaISPC;sem atribuir taxa de outro regime por presunção.';return;}
|
||||
if(i.option==='not_opted'){r.status='not_applicable';r.reason='Sem opçãoISPC para esta operação; não aplicar exclusãoIRPS5nem taxaISPC automaticamente.';return;}
|
||||
if(!['preparation','opted'].includes(i.option)||i.option==='opted'&&(!i.optionRef.trim()||!validDate(i.optionDate)||i.optionDate>i.operationDate)||i.origin==='effective'&&i.option!=='opted')r.missing.push('Opção documentada aplicável à operação efectiva;preparação apenas permite cenário');
|
||||
const annual=amount(i.annual2026,'Volume anual2026 para escalão, distinto do acesso2025',r),prior=amount(i.priorInYear,'Volume anterior no ano2026',r);if(!['forecast','closed_year'].includes(i.annualOrigin)||!i.annualRef.trim())r.missing.push('Referência anual suportada e previsão identificada como cenário');
|
||||
if(base&&prior&&annual&&(cmp(annual,addFractions([base,prior]))<0n||i.annualOrigin==='closed_year'&&i.quarter==='4'&&cmp(annual,addFractions([base,prior]))!==0n))r.missing.push('Reconciliar volume anual com acumulado anterior e trimestre');
|
||||
if(r.missing.length||!base||!prior||!annual)return;
|
||||
const n=cmp(annual,fraction(1000000n))<=0n?3:cmp(annual,fraction(2500000n))<=0n?4:5,ordinary=min(base,positive(subtractFractions(fraction(4000000n),prior))),excess=subtractFractions(base,ordinary),tax=addFractions([rate(ordinary,n),rate(excess,20)]);r.amounts={...r.amounts,ordinary,excess,tax,payment:cmp(tax,fraction(500n))<0n?fraction(0n):tax};r.details.projected=i.origin==='projected'||i.option==='preparation'||i.annualOrigin==='forecast'?'yes':'no';r.details.rate=String(n);r.details.declaration='Mantida mesmo quando prestação inferior500MZN';r.status='calculated';r.reason=`${r.details.projected==='yes'?'Cenário declarado;sem adesão automática.':'Opção e factos efectivos declarados.'} Operações ocasionais próprias3(3–4),base trimestral9,taxa${n}%e20%somente no excesso de vendas acima4.000.000. Não há retenção presumida nem dedução de custos/IVA.`;
|
||||
}
|
||||
function acquisitions(d:Record<string,unknown>,i:Record<string,string>,r:ResidualResult){
|
||||
const w=ispcWithholdingBook(d).input,e=ispcEligibilityBook(d);if(!ispcEligibilityCurrent(d,e)||e.result?.status!=='compatible'||e.result.optionStatus==='not_opted'||e.result.optionStatus==='indeterminate'||e.input.origin==='effective'&&e.result.optionStatus!=='recorded'){r.missing.push('Enquadramento/opção actual do adquirenteISPC');return;}
|
||||
if(w.applicable!=='yes'||w.naturalOccasional!=='yes'||w.unregistered!=='yes'||w.related!=='yes'||!['forestry','fishery','livestock','agriculture','poultry','beekeeping'].includes(w.activity)||!w.reference.trim()){r.missing.push('Condições específicas12(3–4)e suporte no livro das aquisições');return;}
|
||||
const base=amount(w.base,'Base das aquisições',r),prior=amount(w.priorAnnualPurchases,'Aquisições globais anteriores do ano',r);if(!base||!prior)return;const covered=min(base,positive(subtractFractions(fraction(2500000n),prior))),excess=subtractFractions(base,covered);r.amounts={base,prior,covered,excess,coveredTax:rate(covered,5),excessTax:null,total:null};r.details.quarter=w.quarter;r.details.acquisitionRef=w.reference;
|
||||
if(cmp(excess,fraction(0n))<=0n){r.status='not_applicable';r.reason='Sem parcela acima do limite; o cálculo5%já disponível permanece no seu livro, sem segunda liquidação.';return;}
|
||||
r.status='partial';r.reason='Parcela até ao limite separada a5%; parcela excedente quantificada, sem presumir5%ou20%pelo simples excesso. Montante total continua indeterminado até identificar tratamento próprio.';
|
||||
if(i.route==='irps_isolated'){
|
||||
const net=amount(i.grossExcess,'Rendimento ilíquido da parcela excedente, distinto de rendimento líquido e do preço líquido de IVA',r);if(i.noIspcOnExcess!=='yes'||i.isolatedAct!=='yes'||i.incomeInMoz!=='yes'||!i.grossRef.trim()||!i.reference.trim())r.missing.push('Acto isoladoIRPS8(3h,4),rendimento emMoçambique,sem opçãoISPC5aplicável à parcela,e referências da classificação/base');
|
||||
if(net&&cmp(net,excess)!==0n)r.missing.push('Base ilíquida57(4)não coincide com a parcela bruta identificada;reconciliar sem deduzir custos/IVA automaticamente');
|
||||
if(!r.missing.length&&net){r.amounts.excessTax=rate(net,20);r.amounts.total=addFractions([r.amounts.coveredTax!,r.amounts.excessTax]);r.status='calculated';r.reason='Correspondência positiva independente:IRPS57(2k)acto isolado,20%sobre rendimento ilíquido57(4)da parcela identificada,sem opçãoISPCaplicável. Não se usa taxa20%do excesso de vendasISPC. Retenções5%e20%separadas,não são crédito do imposto próprio do adquirente.';}
|
||||
}else if(i.route==='ispc_supplier'){if(!i.supplierOptionRef.trim())r.missing.push('Referência da opção/registoISPCdo fornecedor aplicável a estas operações');r.reason='Fornecedor com opçãoISPC declarada:art5impede aplicarIRPSporpresunção. A parcela fora12(3)exige factura/registo do fornecedor e liquidação própria correspondente; o comprador não atribui5%ou20%automaticamente. Sem total de retenção presumido.';}
|
||||
else r.missing.push('Enquadramento específico da parcela excedente:opçãoISPCdo fornecedor ou acto isoladoIRPS,base e suporte');
|
||||
}
|
||||
function formalities(d:Record<string,unknown>,i:Record<string,string>,r:ResidualResult){
|
||||
let src:ResidualResult|undefined;if(i.sourceKind==='quarter'){const b=ispcQuarterBook(d),v=b.result;if(!v||!ispcQuarterCurrent(d,b)||v.status!=='calculated'){r.missing.push('Apuramento trimestral actual e calculado');return;}r.amounts={base:v.base,tax:v.tax,payment:v.payment,ordinary:v.ordinary,excess:v.excess};r.details={quarter:v.input.quarter,rate:String(v.rate),sourceDate:v.calculatedAt};}
|
||||
else{const b=ispcResidualBook(d,i.sourceKind==='occasional'?'occasional':'acquisitions');src=b.result;if(!src||!ispcResidualCurrent(d,b)){r.missing.push('Resultado actual do percurso seleccionado');return;}if(src.status==='settled_by_withholding'){r.status='not_applicable';r.reason='Operação própria já com retenção liberatória documentada:conservar comprovativo,sem emitir liquidação própria duplicada.';return;}if(src.status!=='calculated'){r.missing.push('Cálculo completo do percurso seleccionado;as partes determinadas permanecem consultáveis');return;}r.amounts={...src.amounts,tax:src.amounts.total??src.amounts.tax,payment:src.amounts.total??src.amounts.payment};r.details={quarter:src.input.quarter||src.details.quarter,rate:src.details.rate||'retenções separadas',sourceDate:src.calculatedAt};}
|
||||
const first=r.amounts.covered??r.amounts.ordinary??r.amounts.base,second=r.amounts.excess??fraction(0n),firstRate=i.sourceKind==='acquisitions'?5:Number(r.details.rate);
|
||||
if(first&&[3,4,5,12,15].includes(firstRate)){const firstTax=r.amounts.coveredTax??rate(first,firstRate),secondTax=r.amounts.excessTax??rate(second,20);r.amounts.q8base01=first;r.amounts.q8tax05=firstTax;r.amounts.q8base02=second;r.amounts.q8tax06=secondTax;r.details.q8rate01=String(firstRate);r.details.q8rate02='20';if(r.amounts.tax&&cmp(addFractions([firstTax,secondTax]),r.amounts.tax)!==0n)r.missing.push('Parcelas do quadro8divergem do cálculo guardado;conferir apenas essa correspondência');}
|
||||
if(i.sourceKind==='acquisitions'&&!(i.retentionFormRef??'').trim())r.missing.push('Modelo/código de entrega da retençãoISPC12(3)e da retençãoIRPS57(2k),distintos do imposto próprio;comunicado9não resolve isoladamente este modelo');
|
||||
if(r.amounts.tax&&r.amounts.payment&&cmp(r.amounts.tax,fraction(0n))>0n&&cmp(r.amounts.tax,fraction(500n))<0n&&cmp(r.amounts.payment,fraction(0n))===0n)r.missing.push('Representação da dispensa de pagamento10-A noB–Geral:declarar imposto apurado sem presumir zero no campo de montante apurado');
|
||||
r.details.model='Modelo B–Geral;comunicadoAT9/2026';r.details.paymentMonth=['Abril2026','Julho2026','Outubro2026','Janeiro2027'][Number(r.details.quarter)-1]||'Trimestre por identificar';r.details.formPeriod=i.formMonth?`${i.formMonth}/${i.formYear}`:'Indeterminado:quadro2pede mês/ano;comunicado identifica trimestre/mês de pagamento,sem resolver a codificação do período';
|
||||
if(!/^[0-9]{9}$/.test(i.nuit)||!i.name.trim()||!i.fiscalArea.trim()||!i.address.trim())r.missing.push('NUIT9dígitos,nome,área fiscal/UGC e domicílio para formalização;preparação do cálculo não exige esses campos');
|
||||
if(!/^(0[1-9]|1[0-2])$/.test(i.formMonth)||!['2026','2027'].includes(i.formYear)||!i.formPeriodRef.trim())r.missing.push('Mês/ano a inscrever no quadro2e instrução/correspondência utilizada; não preencher automaticamente com mês de pagamento');
|
||||
if(!['none','amount'].includes(i.interestSituation)||!i.interestRef.trim())r.missing.push('Situação dos juros compensatórios e suporte;desconhecido não é zero');
|
||||
if(i.interestSituation==='amount')r.amounts.interest=amount(i.interestAmount,'Juros documentados,não calculados por falta de taxa/período regulamentar',r);else if(i.interestSituation==='none')r.amounts.interest=fraction(0n);
|
||||
r.amounts.finalPayment=r.amounts.payment&&r.amounts.interest?addFractions([r.amounts.payment,r.amounts.interest]):null;
|
||||
if(i.externalStatus!=='preparation'&&(!i.externalRef.trim()||!i.externalDate.trim()))r.missing.push('Referência e data da submissão/recepção/pagamento declarado;sem confirmação automáticaAT');
|
||||
r.status=r.missing.length?'partial':'calculated';r.reason='Preparação dos campos identificados do B–Geral,com cálculo e prestação separados. O Modelo30antigo não recebe taxas2026. Submissão,recepção e pagamento são actos externos;este registo conserva referências e histórico,sem os efectuar ou certificar.';
|
||||
}
|
||||
export function priorOccasionalSettlement(b:ResidualBook):ResidualResult|undefined{if(b.kind!=='occasional'||b.input.settlement!=='self')return;return[b.result,...(b.history??[])].find(r=>r?.status==='settled_by_withholding'&&r.input.reference.trim()===b.input.reference.trim()&&r.input.operationDate===b.input.operationDate&&r.input.quarter===b.input.quarter&&r.input.amount===b.input.amount);}
|
||||
export function recordIspcResidual(d:Record<string,unknown>,b:ResidualBook,now=new Date().toISOString()):ResidualBook{validate(b,b.kind);const r:ResidualResult={key:key(d,b),scope:acquisitionScope(d),calculatedAt:now,status:'indeterminate',reason:'Dados específicos em falta;sem presumir zero.',missing:[],input:structuredClone(b.input),amounts:{},details:{},source:residualSources[b.kind]};if(b.kind==='occasional'){occasional(b.input,r);const prior=priorOccasionalSettlement(b);if(prior&&r.status==='calculated'){r.details.priorWithholdingRef=prior.input.withheldRef;r.details.priorWithholdingDate=prior.calculatedAt;if(b.input.withholdingCorrected==='yes'&&(b.input.withholdingCorrectionRef??'').trim()){r.details.withholdingCorrectionRef=b.input.withholdingCorrectionRef;r.reason+=' Correcção da retenção anterior declarada segundo referência externa,sem certificar esse acto;histórico preservado.';}else{r.status='partial';r.amounts.hypotheticalOwnTax=r.amounts.tax;r.amounts.tax=null;r.amounts.payment=null;r.amounts.withheld=prior.amounts.withheld??prior.amounts.tax;r.missing.push('Retenção liberatória anterior para a mesma operação;reconciliar eventual correcção documentada antes de nova prestação própria');r.reason='A via foi alterada,mas a retenção liberatória documentada permanece no histórico. Não é gerada segunda prestação;os dados da operação e as duas versões ficam preservados.';}}}else if(b.kind==='acquisitions')acquisitions(d,b.input,r);else formalities(d,b.input,r);return{...b,...(b.result?{history:[...(b.history??[]),structuredClone(b.result)]}:{}),result:r};}
|
||||
const labels:Record<string,string>={base:'Base',prior:'Acumulado global anterior',ordinary:'Parcela ordinária',excess:'Parcela excedente',tax:'Imposto',payment:'Prestação própria',withheld:'Retenção documentada',hypotheticalOwnTax:'Cálculo próprio apenas hipotético,sem prestação gerada',covered:'Parcela abrangida pelo limite',coveredTax:'Retenção5%da parcela abrangida',excessTax:'RetençãoIRPS20%da parcela qualificada',total:'Total de retenções',interest:'Juros documentados',finalPayment:'Preparação do montante a entregar'};
|
||||
export function ispcResidualReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{const rows:Array<[string,string,string,string]>=[];for(const kind of ['occasional','acquisitions','formalities']as const){try{const b=ispcResidualBook(d,kind),r=b.result;if(!r)continue;const title={occasional:'Operações ocasionais próprias',acquisitions:'Aquisições acima do limite',formalities:'Formalidades2026—B–Geral'}[kind];rows.push(['ISPC',title,`${({calculated:'Calculado',settled_by_withholding:'Retenção liberatória documentada',partial:'Parcial',indeterminate:'Indeterminado',not_applicable:'Não aplicável ao recorte'} as Record<string,string>)[r.status]};${r.reason};falta:${r.missing.join('; ')||'nenhum dado deste recorte'}`,`${ispcResidualCurrent(d,b)?'Entradas correspondentes':'Histórico preservado;rever entradas'};${r.calculatedAt};${r.source}`]);for(const[k,v]of Object.entries(r.amounts).filter(([k])=>!k.startsWith('q8')))rows.push(['ISPC',`${title}—${kind==='formalities'&&r.input.sourceKind==='acquisitions'&&k==='payment'?'Retenções a entregar pelo adquirente':labels[k]||k}`,v?`${fractionPresentation(v).decimal}MZN (${v.numerator}/${v.denominator})`:'Indeterminado',`${r.input.reference||r.details.acquisitionRef||r.input.externalRef||'Pressupostos/documentos declarados'};${r.scope}`]);}catch(e){rows.push(['ISPC','Residual não recuperável',String(e),'Originais preservados.']);}}return rows;}
|
||||
export function ispcFormalPreparationHtml(d:Record<string,unknown>):string{const b=ispcResidualBook(d,'formalities'),r=b.result;if(!r||!ispcResidualCurrent(d,b)||!Object.keys(r.amounts).length)throw Error('Guarde primeiro preparação actual com cálculo identificado.');const esc=(v:unknown)=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]!));const v=(n:string)=>r.amounts[n]?fractionPresentation(r.amounts[n]!).decimal:'Indeterminado';const fields=[['Quadro1—tipo',b.input.declaration==='initial'?'Inicial':'Substituição'],['Quadro2—mês/ano',r.details.formPeriod],['Contexto—trimestre e mês de pagamento',`2026/T${r.details.quarter};${r.details.paymentMonth} (não copiado automaticamente para quadro2)`],['Quadro3—NUIT/ÁreaFiscal',`${b.input.nuit}/${b.input.fiscalArea}`],['Quadro5—nome',b.input.name],['Quadro6—domicílio',b.input.address],['Quadro8—linha1:base01/taxa/montante05',`${b.input.sourceKind==='acquisitions'?'ISPC—retenção12(3)':'ISPC—parcela ordinária'};base01:${v('q8base01')};taxa:${r.details.q8rate01}%;montante05:${v('q8tax05')}`],['Quadro8—linha2:base02/taxa/montante06',r.amounts.q8base02&&cmp(r.amounts.q8base02,fraction(0n))>0n?`${b.input.sourceKind==='acquisitions'?'IRPS—acto isolado57(2k)':'ISPC—excesso de vendas8(1)d'};base02:${v('q8base02')};taxa20%;montante06:${v('q8tax06')}`:'Não aplicável ao cálculo seleccionado;sem segunda parcela'],['Quadro8—subtotal1campo09',v('tax')],['Quadro10—montante/juros/importância',`Imposto calculado:${v('tax')};prestação legal:${v('payment')};juros:${v('interest')};totalpreparado:${v('finalPayment')}`],['Modelo/código das retenções',b.input.retentionFormRef||'Por corresponder se aplicável'],['Estado externo declarado',`${({preparation:'Em preparação',submitted:'Submetido segundo referência declarada',received:'Recebido segundo referência declarada',paid:'Pago segundo referência declarada'} as Record<string,string>)[b.input.externalStatus]};${b.input.externalRef};${b.input.externalDate}`],['Falta',r.missing.join('; ')||'Nenhum dado deste recorte']];return`<!doctype html><html lang="pt"><meta charset="utf-8"><title>PreparaçãoISPC—B–Geral</title><style>body{font:16px system-ui;margin:32px}td,th{border:1px solid #777;padding:10px;vertical-align:top}table{border-collapse:collapse;width:100%}</style><h1>Preparação de campos ISPC—Modelo B–Geral</h1><p>Correspondência de apoio; não é formulário oficial emitido, declaração submetida ou comprovativo de pagamento. Original e instrução AT preservados,sem os alterar.</p><table>${fields.map(([a,c])=>`<tr><th>${esc(a)}</th><td>${esc(c)}</td></tr>`).join('')}</table><p>${esc(r.source)}</p><p>Quadros8e10têm numeração própria;campos homónimos não são somados entre quadros. Não preencher área de serviços nem assinatura automaticamente.</p></html>`;}
|
||||
@@ -0,0 +1,24 @@
|
||||
import {ispcEligibilityBook,ispcEligibilityCurrent} from './ispc-eligibility.ts';
|
||||
import {acquisitionScope} from './iva-acquisitions.ts';
|
||||
import {addFractions,decimalFraction,fraction,fractionPresentation,type FiscalFraction} from './fiscal-rational.ts';
|
||||
export type IspcWithholdingInput={applicable:''|'no'|'yes';quarter:string;base:string;priorAnnualPurchases:string;naturalOccasional:''|'yes'|'no';unregistered:''|'yes'|'no';related:''|'yes'|'no';activity:''|'forestry'|'fishery'|'livestock'|'agriculture'|'poultry'|'beekeeping'|'other';reference:string;};
|
||||
export type IspcWithholdingResult={input:IspcWithholdingInput;key:string;status:'calculated'|'indeterminate'|'not_applicable';reason:string;withheld:FiscalFraction|null;calculatedAt:string;source:string};
|
||||
export type IspcWithholdingBook={version:1;input:IspcWithholdingInput;result?:IspcWithholdingResult;history?:IspcWithholdingResult[]};
|
||||
export const ispcWithholdingSource='Lei9/2025,republicaçãoISPC,arts3(3–4),12(3–4);PDF10–11/p2180(10–11). Retenção liberatória5% sobre aquisição a pessoa singular ocasional não inscrita, ligada à actividade, até limite global anual2.500.000MZN; factura por conta do fornecedor e entrega trimestral em modelo próprio. Não é crédito contra o imposto próprio nem se aplica o mínimo500 desta prestação à retenção.';
|
||||
const blank=():IspcWithholdingInput=>({applicable:'',quarter:'1',base:'',priorAnnualPurchases:'',naturalOccasional:'',unregistered:'',related:'',activity:'',reference:''});
|
||||
function snapshot(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 não recuperáveis; originais preservados.');return s;}
|
||||
function validate(b:IspcWithholdingBook){if(!b||b.version!==1||!b.input||Object.keys(blank()).some(k=>typeof b.input[k as keyof IspcWithholdingInput]!=='string')||['applicable','naturalOccasional','unregistered','related'].some(k=>!['','yes','no'].includes(b.input[k as keyof IspcWithholdingInput]))||!['','forestry','fishery','livestock','agriculture','poultry','beekeeping','other'].includes(b.input.activity)||b.history!==undefined&&!Array.isArray(b.history))throw Error('RetençõesISPC não recuperáveis; originais preservados.');}
|
||||
function map(d:Record<string,unknown>):Record<string,IspcWithholdingBook>{const v=snapshot(d).ispcWithholdings;if(v===undefined)return{};if(!v||typeof v!=='object'||Array.isArray(v))throw Error('Mapa de retençõesISPC inválido.');return v;}
|
||||
export function ispcWithholdingBook(d:Record<string,unknown>):IspcWithholdingBook{const b=map(d)[acquisitionScope(d)]??{version:1,input:blank()};validate(b);return b;}
|
||||
export function saveIspcWithholdingBook(d:Record<string,unknown>,b:IspcWithholdingBook):string{validate(b);return JSON.stringify({...snapshot(d),ispcWithholdings:{...map(d),[acquisitionScope(d)]:b}});}
|
||||
export function recordIspcWithholding(d:Record<string,unknown>,b:IspcWithholdingBook,now=new Date().toISOString()):IspcWithholdingBook{validate(b);const i=b.input,e=ispcEligibilityBook(d),r:IspcWithholdingResult={input:structuredClone(i),key:JSON.stringify([acquisitionScope(d),i]),status:'indeterminate',reason:'Identifique se existem aquisições abrangidas; não presumir retenção zero.',withheld:null,calculatedAt:now,source:ispcWithholdingSource};
|
||||
if(i.applicable==='no'){r.status='not_applicable';r.reason='Sem aquisições abrangidas, segundo declaração expressa; entradas anteriores preservadas.';}
|
||||
else if(i.applicable==='yes'&&(!ispcEligibilityCurrent(d,e)||e.result?.status!=='compatible'||e.result.optionStatus==='not_opted'||e.result.optionStatus==='indeterminate'||e.input.origin==='effective'&&e.result.optionStatus!=='recorded')){r.reason='Guarde o enquadramento e a opção aplicáveis do adquirenteISPC antes de calcular retenção efectiva; sem inferir adesão.';}
|
||||
else if(i.applicable==='yes'){
|
||||
if(i.naturalOccasional==='no'||i.unregistered==='no'||i.related==='no'||i.activity==='other'){r.status='not_applicable';r.reason='Aquisição fora do recorte12(3–4) declarado; outros regimes de retenção mantêm análise própria,sem presumir isenção.';}
|
||||
else if(i.naturalOccasional==='yes'&&i.unregistered==='yes'&&i.related==='yes'&&i.activity&&i.reference.trim()&&['1','2','3','4'].includes(i.quarter)){
|
||||
try{const base=decimalFraction(i.base),prior=decimalFraction(i.priorAnnualPurchases),total=addFractions([base,prior]);if(BigInt(total.numerator)>2500000n*BigInt(total.denominator))r.reason='Total global anual superior2.500.000MZN: tratamento da aquisição acima do limite por corresponder; não reter automaticamente5% nem truncar a base.';else{r.status='calculated';r.withheld=fraction(BigInt(base.numerator)*5n,BigInt(base.denominator)*100n);r.reason='Retenção5% calculada separadamente do imposto próprio; emitir factura por conta do fornecedor e preparar entrega trimestral em modelo próprio. Sem deduzir esta retenção da prestaçãoISPC.';}}catch{r.reason='Base e aquisições globais anteriores do ano necessários,incluindo zero expresso; não presumir montantes.';}
|
||||
}else r.reason='Identifique pessoa singular ocasional3(3–4),actividade abrangida,não inscrição,ligação à actividade,trimestre e suporte; dados desconhecidos não viram não aplicáveis.';
|
||||
}
|
||||
return{...b,...(b.result?{history:[...(b.history??[]),structuredClone(b.result)]}:{}),result:r};}
|
||||
export function ispcWithholdingReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=ispcWithholdingBook(d),r=b.result;if(!r)return[];return[['ISPC','Retenção em aquisições ocasionais',`${r.status}; ${r.withheld?fractionPresentation(r.withheld).decimal+' MZN':'Indeterminado/não aplicado'}; ${r.reason}`,`2026/T${r.input.quarter}; base:${r.input.base}; anteriores globais:${r.input.priorAnnualPurchases}; suporte:${r.input.reference}; ${r.key===JSON.stringify([acquisitionScope(d),b.input])?'Entradas correspondentes':'Histórico preservado;rever entradas'}; ${r.calculatedAt}; ${r.source}`]];}catch(e){return[['ISPC','Retenção não recuperável',String(e),'Originais preservados.']];}}
|
||||
@@ -175,6 +175,7 @@ const rowSection: Record<string, DossierReportSectionId> = {
|
||||
Orçamento: 'finance',
|
||||
Tesouraria: 'finance',
|
||||
'IVA mensal': 'finance',
|
||||
ISPC: 'finance',
|
||||
Equipa: 'team',
|
||||
'Necessidade de negócio': 'resources',
|
||||
Financiamento: 'resources',
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {ispcResidualReportRows} from './ispc-residuals.ts';
|
||||
import {ispcWithholdingReportRows} from './ispc-withholding.ts';
|
||||
import {ispcQuarterReportRows} from './ispc-quarter.ts';
|
||||
import {ispcEligibilityReportRows} from './ispc-eligibility.ts';
|
||||
import {fiscalCalculationGapReportRows} from './iva-calculation-gaps.ts';
|
||||
import {l3FormPreparationReportRows} from './l3-form-preparation.ts';
|
||||
import { remissionReportRows } from './iva-remission-imports.ts';
|
||||
@@ -685,6 +689,10 @@ export function buildProjectDossierRows(
|
||||
rows.push(...travelReportRows(draft));
|
||||
rows.push(...travelEventReportRows(draft));
|
||||
rows.push(...offerPreparationReportRows(draft));
|
||||
rows.push(...ispcEligibilityReportRows(draft));
|
||||
rows.push(...ispcQuarterReportRows(draft));
|
||||
rows.push(...ispcWithholdingReportRows(draft));
|
||||
rows.push(...ispcResidualReportRows(draft));
|
||||
rows.push(...fiscalCalculationGapReportRows(draft));
|
||||
rows.push(...l3FormPreparationReportRows(draft));
|
||||
const operationRows = salesReportRows(draft);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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 IspcQuarterDraftTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
public function test_quarter_and_option_recover_privately_without_changing_accepted_fiscal_books(): 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]);$actor=User::factory()->create(['email_verified_at'=>now()]);$this->actingAs($actor);
|
||||
$draft=json_decode(file_get_contents(base_path('tests/frontend/fixtures/ispc-quarter-preserved.json')),true,flags:JSON_THROW_ON_ERROR);
|
||||
$personal=['person_type'=>'collective'];unset($draft['person_type']);
|
||||
$id=$this->postJson('/api/v1/simulation-drafts',['personal_snapshot'=>$personal,'economic_snapshot'=>$draft],['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id');
|
||||
$recovered=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk()->json('data.economic_snapshot');$this->assertSame($draft['modelo_a_snapshot'],$recovered['modelo_a_snapshot']);
|
||||
$s=json_decode($recovered['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);$r=$s['ispcQuarters']['opportunity:375']['result'];$this->assertSame('calculated',$r['status']);$this->assertSame(['numerator'=>'24000','denominator'=>'1'],$r['tax']);$this->assertSame($r['tax'],$r['payment']);$this->assertTrue($r['declaration']);$this->assertFalse($r['projected']);$this->assertSame('recorded',$r['eligibility']['optionStatus']);$this->assertSame('SYNTHETIC QA opção ISPC2026',$r['eligibility']['input']['optionReference']);$this->assertNotEmpty($s['ispcQuarters']['opportunity:375']['history']);
|
||||
$seed=json_decode(file_get_contents(base_path('tests/frontend/fixtures/iva-l3e-preserved.json')),true,flags:JSON_THROW_ON_ERROR);foreach(json_decode($seed['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR)as$key=>$value)$this->assertSame($value,$s[$key]);
|
||||
$this->actingAs(User::factory()->create(['email_verified_at'=>now()]));$this->getJson('/api/v1/simulation-drafts/'.$id)->assertNotFound();$this->actingAs($actor);$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk();
|
||||
if(is_dir(base_path('outputs/ispc-l4b-20261025')))file_put_contents(base_path('outputs/ispc-l4b-20261025/recovered.json'),json_encode($recovered,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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 IspcResidualDraftTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
public function test_new_residual_books_recover_without_rewriting_installed_habitual_or_L3_results():void
|
||||
{
|
||||
$t=DB::selectOne('select current_database() as name,inet_server_port() as port');$this->assertSame('simulator_fiscal_delta_20261021_test',$t->name);$this->assertSame(55441,(int)$t->port);config(['investor-path.enabled'=>true,'suitecrm.enabled'=>false]);$this->actingAs(User::factory()->create(['email_verified_at'=>now()]));
|
||||
$d=json_decode(file_get_contents(base_path('tests/frontend/fixtures/ispc-residual-preserved.json')),true,flags:JSON_THROW_ON_ERROR);$personal=['person_type'=>$d['person_type']];unset($d['person_type']);
|
||||
$id=$this->postJson('/api/v1/simulation-drafts',['personal_snapshot'=>$personal,'economic_snapshot'=>$d],['Idempotency-Key'=>(string)Str::uuid()])->assertCreated()->json('data.id');$recovered=$this->getJson('/api/v1/simulation-drafts/'.$id)->assertOk()->json('data.economic_snapshot');$this->assertSame($d['modelo_a_snapshot'],$recovered['modelo_a_snapshot']);$s=json_decode($recovered['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR);
|
||||
$own=$s['ispcResiduals']['opportunity:376']['occasional']['result'];$this->assertSame('calculated',$own['status']);$this->assertSame(['numerator'=>'3000','denominator'=>'1'],$own['amounts']['tax']);$this->assertSame('singular',$own['input']['personType']);
|
||||
$a=$s['ispcResiduals']['opportunity:375']['acquisitions']['result'];$this->assertSame('calculated',$a['status']);$this->assertSame(['numerator'=>'5000','denominator'=>'1'],$a['amounts']['coveredTax']);$this->assertSame(['numerator'=>'20000','denominator'=>'1'],$a['amounts']['excessTax']);$this->assertSame(['numerator'=>'25000','denominator'=>'1'],$a['amounts']['total']);
|
||||
$this->assertSame('partial',$s['ispcResiduals']['opportunity:375']['formalities']['result']['status']);$this->assertStringContainsString('Indeterminado',$s['ispcResiduals']['opportunity:375']['formalities']['result']['details']['formPeriod']);
|
||||
$old=json_decode(file_get_contents(base_path('tests/frontend/fixtures/ispc-quarter-preserved.json')),true,flags:JSON_THROW_ON_ERROR);foreach(json_decode($old['modelo_a_snapshot'],true,flags:JSON_THROW_ON_ERROR)as$key=>$value){if($key==='ispcWithholdings')continue;if($key==='ispcEligibility'){foreach($value as$ctx=>$book)$this->assertSame($book,$s[$key][$ctx]);}else$this->assertSame($value,$s[$key]);}
|
||||
if(is_dir(base_path('outputs/ispc-residuals-20261025')))file_put_contents(base_path('outputs/ispc-residuals-20261025/recovered.json'),json_encode($recovered,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
|
||||
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
||||
import {newIspcEligibilityInput,ispcEligibilityBook,saveIspcEligibilityBook,recordIspcEligibility,ispcEligibilityCurrent,ispcEligibilityReportRows,ispcReuseValues,ispcReuseDiff} from '../../resources/js/lib/ispc-eligibility.ts';
|
||||
const seed=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-l3e-preserved.json',import.meta.url),'utf8'));
|
||||
function fixture(patch={}){const d={...structuredClone(seed),context_opportunity:'opportunity:375',fiscal_component:'ispc',person_type:'collective',fiscal_activity:'SYNTHETIC QA comércio',fiscal_establishments:'1',project_title:'SYNTHETIC QA — L4-A ISPC'},input={...newIspcEligibilityInput(d),activities:['commerce'],territory:'yes',basis:'previous_year',referenceYear:'2025',annualReference:'4000000',annualReferenceRef:'SYNTHETIC QA referência2025',organizedRequired:'no',sharesInIspc:'no',sharesAnonymous:'no',otherActivities:'no',generalRegimeChosen:'no',...patch};return{d,b:{version:1,input}};}
|
||||
const evaluate=patch=>{const{d,b}=fixture(patch);return recordIspcEligibility(d,b).result;};
|
||||
test('reuses only valid person/activity/establishments;does not invent activity category,prior annual volume or option',()=>{const d={person_type:'sole_trader',fiscal_activity:'Actividade conhecida',fiscal_establishments:2,currency:'MZN',annual_sales:'3000000',fiscal_turnover:'3000000'};const i=newIspcEligibilityInput(d);assert.equal(i.personType,'singular');assert.equal(i.establishments,'2');assert.equal(i.activityDescription,'Actividade conhecida');assert.deepEqual(i.activities,[]);assert.equal(i.annualReference,'');assert.equal(i.option,'preparation');assert.equal(newIspcEligibilityInput({...d,person_type:'consortium'}).personType,'');});
|
||||
test('2025reference4000000inclusive is compatible;optative choice remains preparation;foreign investor does not imply foreign operation',()=>{const{d,b}=fixture();d.nationality='estrangeira';const r=recordIspcEligibility(d,b).result;assert.equal(r.status,'compatible',r.reason);assert.equal(r.annualReference.numerator,'4000000');assert.equal(r.optionStatus,'preparation');assert.match(r.optionReason,/não é adesão/);assert.equal(evaluate({annualReference:'4000000.000001'}).status,'incompatible');assert.equal(evaluate({annualReference:''}).status,'indeterminate');assert.equal(evaluate({annualReference:'0'}).status,'compatible');});
|
||||
test('known statutory exclusions are specific and do not require filling irrelevant remaining inputs',()=>{for(const patch of [{organizedRequired:'yes'},{sharesInIspc:'yes'},{sharesAnonymous:'yes'},{otherActivities:'yes'},{activities:['other']},{establishments:'2'},{territory:'no'}])assert.equal(evaluate({...patch,annualReference:''}).status,'incompatible',JSON.stringify(patch));for(const field of ['organizedRequired','sharesInIspc','sharesAnonymous','otherActivities','generalRegimeChosen'])assert.equal(evaluate({[field]:''}).status,'indeterminate',field);});
|
||||
test('liberal183days versus184;8b services do not inherit the8c duration rule;inapplicable retained facts do not become exclusions',()=>{const p={activities:['liberal15'],unlistedServices:'no',liberalDaysSameEntity:'183',liberalClientRef:'SYNTHETIC QA maior duração do ano'};assert.equal(evaluate(p).status,'compatible');assert.equal(evaluate({...p,liberalDaysSameEntity:'184'}).status,'incompatible');assert.equal(evaluate({...p,liberalDaysSameEntity:''}).status,'indeterminate');assert.equal(evaluate({...p,liberalDaysSameEntity:'367'}).status,'indeterminate');assert.equal(evaluate({...p,activities:['services12'],liberalDaysSameEntity:'184'}).status,'compatible');assert.equal(evaluate({...p,activities:['commerce'],unlistedServices:'yes',liberalDaysSameEntity:'184'}).status,'compatible');assert.equal(evaluate({...p,activities:['commerce','liberal15'],liberalDaysSameEntity:'184'}).status,'incompatible');});
|
||||
test('startup forecast has its own2026basis and AT confirmation;projected assumption and effective reference stay distinct',()=>{const p={basis:'start_forecast',referenceYear:'2026',annualReference:'1000000'};assert.equal(evaluate(p).status,'indeterminate');assert.equal(evaluate({...p,forecastConfirmed:'yes'}).status,'compatible');assert.equal(evaluate({...p,origin:'effective',forecastConfirmed:'yes'}).status,'indeterminate');assert.equal(evaluate({...p,origin:'effective',forecastConfirmed:'yes',forecastConfirmationRef:'SYNTHETIC QA confirmaçãoAT'}).status,'compatible');assert.equal(evaluate({...p,referenceYear:'2025',forecastConfirmed:'yes',annualReference:'5000000'}).status,'indeterminate');assert.equal(evaluate({basis:'',referenceYear:'',annualReference:'5000000'}).status,'indeterminate');});
|
||||
test('three-year general-regime commitment is explicit;no new approver or assumption from an empty field',()=>{const p={generalRegimeChosen:'yes',generalThreeYearsCompleted:'no'};assert.equal(evaluate(p).status,'incompatible');assert.equal(evaluate({...p,generalThreeYearsCompleted:'yes'}).status,'indeterminate');assert.equal(evaluate({...p,generalThreeYearsCompleted:'yes',generalRegimeRef:'SYNTHETIC QA opção e período cumprido'}).status,'compatible');assert.equal(evaluate({generalRegimeChosen:'no',generalThreeYearsCompleted:'no'}).status,'compatible');});
|
||||
test('documented option is separate from eligibility and cannot be inferred from selectingISPC',()=>{const p={option:'opted'};let r=evaluate(p);assert.equal(r.status,'compatible');assert.equal(r.optionStatus,'indeterminate');r=evaluate({...p,optionReference:'SYNTHETIC QA opção',optionDate:'2025-12-31'});assert.equal(r.optionStatus,'recorded');assert.equal(evaluate({...p,optionReference:'x',optionDate:'2026-02-01'}).optionStatus,'indeterminate');assert.equal(evaluate({option:'not_opted'}).optionStatus,'not_opted');});
|
||||
test('wrong currency/year and occasional scope remain indeterminate rather than zero or invented ineligibility',()=>{for(const patch of [{currency:'USD'},{currency:''},{assessmentDate:'2025-12-31'},{assessmentDate:'2026-02-30'},{assessmentDate:'2027-01-01'},{mode:'occasional'},{personType:''},{referenceYear:'2026'},{establishments:''}])assert.equal(evaluate(patch).status,'indeterminate',JSON.stringify(patch));});
|
||||
test('save/recovery preserves all prior fiscal maps;deliberate edits keep frozen report and append history only on calculation',()=>{const{d,b}=fixture(),before=JSON.parse(d.modelo_a_snapshot);let book=recordIspcEligibility(d,b,'2026-10-25T14:00:00Z');d.modelo_a_snapshot=saveIspcEligibilityBook(d,book);for(const[k,v]of Object.entries(before))assert.deepEqual(JSON.parse(d.modelo_a_snapshot)[k],v,k);assert.ok(ispcEligibilityCurrent(d,book));const first=structuredClone(book.result);book.input.activityDescription='Deliberate future edit';d.modelo_a_snapshot=saveIspcEligibilityBook(d,book);assert.equal(ispcEligibilityCurrent(d,book),false);assert.doesNotMatch(ispcEligibilityReportRows(d).flat().join(' '),/Deliberate future edit/);book=recordIspcEligibility(d,book);assert.deepEqual(book.history.at(-1),first);d.modelo_a_snapshot=saveIspcEligibilityBook(d,book);assert.deepEqual(ispcEligibilityBook(JSON.parse(JSON.stringify(d))),book);});
|
||||
test('reuse differences are reviewable;new profile values do not overwrite annual amounts,option or deliberate edits',()=>{const{d,b}=fixture();b.input.activityDescription='Deliberate activity';b.input.option='not_opted';const diff=ispcReuseDiff({...d,fiscal_establishments:'2',fiscal_activity:'New profile activity'},b);assert.equal(b.input.establishments,'1');assert.equal(b.input.activityDescription,'Deliberate activity');assert.ok(diff.some(v=>v.field==='establishments'&&v.after==='2'));assert.ok(diff.some(v=>v.field==='activityDescription'));assert.ok(!('annualReference'in ispcReuseValues({...d,annual_sales:'9000000'})));assert.equal(b.input.option,'not_opted');});
|
||||
test('malformed books and ambiguous opportunity are preserved errors,not silently empty preparations',()=>{const{d,b}=fixture();b.input.activities=['commerce','commerce'];assert.throws(()=>saveIspcEligibilityBook(d,b),/não recuperáveis/);assert.throws(()=>ispcEligibilityBook({...d,modelo_a_snapshot:JSON.stringify({version:1,books:{},ispcEligibility:[]})}),/não recuperável/);assert.throws(()=>ispcEligibilityBook({...d,context_opportunity:'',context_applicability_snapshot:JSON.stringify({opportunity_choices:['a','b']})}),/Escolha/);});
|
||||
test('export synthetic eligibility book for isolated private persistence and actual component proof',()=>{const{d,b}=fixture({annualReference:'2500000'});let book=recordIspcEligibility(d,b,'2026-10-25T14:00:00Z');book=recordIspcEligibility(d,book,'2026-10-25T14:01:00Z');d.modelo_a_snapshot=saveIspcEligibilityBook(d,book);assert.equal(book.result.status,'compatible');assert.equal(book.result.optionStatus,'preparation');if(process.env.L4A_ISPC_OUTPUT)fs.writeFileSync(process.env.L4A_ISPC_OUTPUT,JSON.stringify(d));});
|
||||
@@ -0,0 +1,18 @@
|
||||
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
|
||||
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
||||
import {newIspcEligibilityInput,recordIspcEligibility,saveIspcEligibilityBook} from '../../resources/js/lib/ispc-eligibility.ts';
|
||||
import {newIspcQuarterInput,ispcQuarterBook,recordIspcQuarter,saveIspcQuarterBook,ispcQuarterCurrent,ispcQuarterReportRows} from '../../resources/js/lib/ispc-quarter.ts';
|
||||
const seed=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-l3e-preserved.json',import.meta.url),'utf8'));
|
||||
function fixture(ep={},qp={}){let d={...structuredClone(seed),context_opportunity:'opportunity:375',project_title:'SYNTHETIC QA — L4 ISPC',fiscal_component:'ispc',currency:'MZN',person_type:'collective',fiscal_activity:'SYNTHETIC QA canalização',fiscal_establishments:'1'};const input={...newIspcEligibilityInput(d),activities:['services12'],territory:'yes',basis:'previous_year',referenceYear:'2025',annualReference:'1000000',annualReferenceRef:'SYNTHETIC QA acesso2025',organizedRequired:'no',sharesInIspc:'no',sharesAnonymous:'no',otherActivities:'no',generalRegimeChosen:'no',unlistedServices:'no',...ep};const e=recordIspcEligibility(d,{version:1,input},'2026-10-25T12:00:00Z');d.modelo_a_snapshot=saveIspcEligibilityBook(d,e);const b={version:1,input:{...newIspcQuarterInput(),sales:['100000','','',''],salesRefs:['SYNTHETIC QA T1','','',''],coverage:'all_taxpayer_activity',...qp}};return{d,b};}
|
||||
const calc=(ep={},qp={})=>{const{d,b}=fixture(ep,qp);return recordIspcQuarter(d,b,'2026-10-25T12:01:00Z').result;};
|
||||
const decimal=x=>Number(x.numerator)/Number(x.denominator);
|
||||
test('quarterly services12 andliberal15;highest mixed rate applied to entire quarterly base;no costs or VAT deduction',()=>{assert.equal(decimal(calc().tax),12000);assert.equal(decimal(calc({activities:['commerce','services12']}).tax),12000);assert.equal(decimal(calc({activities:['services12','liberal15'],liberalDaysSameEntity:'100',liberalClientRef:'QA'}).tax),15000);assert.equal(calc().projected,true);});
|
||||
test('annual goods tiers applied to quarter without splitting annual limits or using previous-year accessvolume',()=>{for(const[annual,rate]of [['1000000',3],['1000000.000001',4],['2500000',4],['2500000.000001',5],['4000000',5]]){const r=calc({activities:['commerce']},{annualBandVolume:annual,annualBandOrigin:'forecast',annualBandRef:'QAannual2026'});assert.equal(r.status,'calculated',r.reason);assert.equal(r.rate,rate);assert.equal(decimal(r.tax),1000*rate);}assert.equal(calc({activities:['commerce']}).status,'indeterminate');});
|
||||
test('20percent only newly crossed excess;prior quarters prevent repeating same excess;no threshold divided byfour',()=>{const q={quarter:'3',sales:['2000000','1900000','200000',''],salesRefs:['QA1','QA2','QA3','']};const r=calc({},q);assert.equal(decimal(r.ordinary),100000);assert.equal(decimal(r.excess),100000);assert.equal(decimal(r.tax),32000);const next=calc({},{...q,quarter:'4',sales:['2000000','1900000','200000','100000'],salesRefs:['QA1','QA2','QA3','QA4']});assert.equal(decimal(next.ordinary),0);assert.equal(decimal(next.tax),20000);});
|
||||
test('minimum500:below no payment,declaration stays;exact500 payable;explicitzero distinct from missing',()=>{let r=calc({activities:['liberal15'],liberalDaysSameEntity:'100',liberalClientRef:'QA'},{sales:['3000','','','']});assert.equal(decimal(r.tax),450);assert.equal(decimal(r.payment),0);assert.equal(r.declaration,true);r=calc({activities:['commerce']},{sales:['16666.666667','','',''],annualBandVolume:'1000000',annualBandOrigin:'forecast',annualBandRef:'QA'});assert.ok(decimal(r.payment)>500);r=calc({}, {sales:['0','','','']});assert.equal(r.status,'calculated');assert.equal(decimal(r.tax),0);assert.equal(calc({}, {sales:['','','','']}).status,'indeterminate');const exact=calc({activities:['commerce']},{sales:['12500','','',''],annualBandVolume:'2000000',annualBandOrigin:'forecast',annualBandRef:'QA'});assert.equal(decimal(exact.payment),500);});
|
||||
test('effective tax needs recorded option;notopted and incompatible are notapplicable;preparation remains scenario only',()=>{assert.equal(calc({origin:'effective'}).status,'indeterminate');assert.equal(calc({option:'not_opted'}).status,'not_applicable');assert.equal(calc({organizedRequired:'yes'}).status,'not_applicable');const r=calc({origin:'effective',option:'opted',optionDate:'2026-01-01',optionReference:'QA opção'});assert.equal(r.status,'calculated');assert.equal(r.projected,false);assert.equal(calc({origin:'effective',assessmentDate:'2026-10-25',option:'opted',optionDate:'2026-10-01',optionReference:'QA opção'}).status,'indeterminate');});
|
||||
test('missing prior quarter,scope,year,source andannual mismatch do not produce zero',()=>{for(const p of [{year:'2025'},{quarter:'5'},{coverage:''},{salesRefs:['','','','']},{quarter:'2',sales:['','1000','','']}])assert.equal(calc({},p).status,'indeterminate');assert.equal(calc({activities:['commerce']},{annualBandVolume:'99999',annualBandOrigin:'forecast',annualBandRef:'QA'}).status,'indeterminate');});
|
||||
test('closed-yearannual mustequalallfourquarters;quarter amount is not annual base',()=>{const q={quarter:'4',sales:['100000','200000','300000','400000'],salesRefs:['QA1','QA2','QA3','QA4'],annualBandVolume:'1000000',annualBandOrigin:'closed_year',annualBandRef:'QA2026'};assert.equal(decimal(calc({activities:['commerce']},q).tax),12000);assert.equal(calc({activities:['commerce']},{...q,annualBandVolume:'1000001'}).status,'indeterminate');assert.equal(decimal(calc({activities:['commerce']},{...q,quarter:'1'}).tax),3000);});
|
||||
test('eligibility edits invalidate dependent calculation;save recovery freezesinput andretainsotherbooks/history',()=>{let{d,b}=fixture();const old=JSON.parse(d.modelo_a_snapshot);b=recordIspcQuarter(d,b);d.modelo_a_snapshot=saveIspcQuarterBook(d,b);assert.deepEqual(JSON.parse(d.modelo_a_snapshot).books,old.books);assert.equal(ispcQuarterCurrent(d,ispcQuarterBook(d)),true);const recovered=ispcQuarterBook(JSON.parse(JSON.stringify(d)));recovered.input.sales[0]='200000';assert.equal(ispcQuarterCurrent(d,recovered),false);assert.equal(decimal(recovered.result.tax),12000);const next=recordIspcQuarter(d,recovered);assert.equal(decimal(next.result.tax),24000);assert.equal(next.history.length,1);assert.equal(decimal(next.history[0].tax),12000);const s=JSON.parse(d.modelo_a_snapshot);s.ispcEligibility['opportunity:375'].input.activityDescription='edited';d.modelo_a_snapshot=JSON.stringify(s);assert.equal(recordIspcQuarter(d,next).result.status,'indeterminate');});
|
||||
test('invalidstoredmaps andambiguouscontext remainpreservederrors',()=>{let{d,b}=fixture();const s=JSON.parse(d.modelo_a_snapshot);s.ispcQuarters=[];assert.throws(()=>ispcQuarterBook({...d,modelo_a_snapshot:JSON.stringify(s)}));assert.throws(()=>saveIspcQuarterBook(d,{...b,input:{...b.input,sales:['1']}}));});
|
||||
test('export completeeligibilityoptioncalculationfixture andreport from recovereddata',()=>{let{d,b}=fixture({origin:'effective',assessmentDate:'2026-10-25',option:'opted',optionDate:'2026-01-01',optionReference:'SYNTHETIC QA opção ISPC2026'},{quarter:'2',sales:['100000','200000','',''],salesRefs:['SYNTHETIC QA T1','SYNTHETIC QA T2','','']});b=recordIspcQuarter(d,b,'2026-10-25T12:01:00Z');d.modelo_a_snapshot=saveIspcQuarterBook(d,b);const recovered=JSON.parse(JSON.stringify(d));assert.equal(decimal(ispcQuarterBook(recovered).result.tax),24000);assert.equal(ispcQuarterBook(recovered).result.projected,false);assert.match(JSON.stringify(ispcQuarterReportRows(recovered)),/24000.00/);const report=createProjectDossierReport(recovered,{selectedSections:new Set(['finance']),version:'QA ISPC',generatedAt:'2026-10-25T12:02:00Z'});assert.match(JSON.stringify(report.sections),/24000.00/);assert.match(JSON.stringify(report.sections),/opção ISPC2026/);if(process.env.L4_ISPC_OUTPUT)fs.writeFileSync(process.env.L4_ISPC_OUTPUT,JSON.stringify(recovered,null,2));});
|
||||
@@ -0,0 +1,33 @@
|
||||
import {ispcEligibilityBook,saveIspcEligibilityBook}from '../../resources/js/lib/ispc-eligibility.ts';
|
||||
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
||||
import {ispcResidualBook,saveIspcResidualBook,recordIspcResidual,ispcResidualCurrent,ispcResidualReportRows,ispcFormalPreparationHtml}from '../../resources/js/lib/ispc-residuals.ts';
|
||||
import {ispcWithholdingBook,saveIspcWithholdingBook}from '../../resources/js/lib/ispc-withholding.ts';
|
||||
import {createProjectDossierReport}from '../../resources/js/lib/project-dossier-report.ts';
|
||||
const seed=JSON.parse(fs.readFileSync(new URL('./fixtures/ispc-quarter-preserved.json',import.meta.url),'utf8'));
|
||||
function own(p={}){const d=structuredClone(seed),b=ispcResidualBook(d,'occasional');b.input={...b.input,personType:'singular',currency:'MZN',origin:'projected',operationDate:'2026-06-15',quarter:'2',noHabitual:'yes',territory:'yes',sporadic:'yes',activity:'agriculture',reference:'SYNTHETIC QA colheita não reiterada',amount:'100000',allQuarterOperations:'yes',priorYearTurnover:'0',priorYearRef:'SYNTHETIC QA2025zeroexpresso',organizedRequired:'no',option:'preparation',optionRef:'',optionDate:'',settlement:'self',annual2026:'100000',annualOrigin:'forecast',annualRef:'SYNTHETIC QA2026',priorInYear:'0',...p};return{d,b};}
|
||||
function acq(p={},wpatch={}){const d=structuredClone(seed),w=ispcWithholdingBook(d);w.input={...w.input,applicable:'yes',quarter:'2',base:'200000',priorAnnualPurchases:'2400000',naturalOccasional:'yes',unregistered:'yes',related:'yes',activity:'agriculture',reference:'SYNTHETIC QA aquisição/ordem e acumulado',...wpatch};d.modelo_a_snapshot=saveIspcWithholdingBook(d,w);const b=ispcResidualBook(d,'acquisitions');b.input={...b.input,...p};return{d,b};}
|
||||
const calc=({d,b})=>recordIspcResidual(d,b,'2026-10-25T15:40:00Z');const number=x=>x?Number(x.numerator)/Number(x.denominator):null;
|
||||
test('positive ownoccasional agricultural isolated8h route;self3/4/5 andnoautomaticIRPS20',()=>{for(const[annual,n]of [['100000',3],['2000000',4],['3000000',5]]){const r=calc(own({annual2026:annual})).result;assert.equal(r.status,'calculated',r.missing.join(';'));assert.equal(number(r.amounts.tax),1000*n);assert.match(r.source,/8\(3h,4\)/);assert.equal(r.details.IRPS.includes('Não se infere'),true);}});
|
||||
test('unknown notnonapplicable;known exclusions andactivityfamilyownscope',()=>{assert.equal(calc(own({personType:''})).result.status,'indeterminate');for(const p of [{personType:'collective'},{noHabitual:'no'},{sporadic:'no'},{territory:'no'},{activity:'other'}])assert.equal(calc(own(p)).result.status,'not_applicable');for(const p of [{territory:''},{currency:'USD'},{quarter:'3'},{reference:''},{priorYearTurnover:''},{organizedRequired:''}])assert.equal(calc(own(p)).result.status,'indeterminate');});
|
||||
test('ownminimum500withoutlosingdeclaration;zeroexplicit and4mexcessnotreused',()=>{let r=calc(own({amount:'1000'})).result;assert.equal(number(r.amounts.tax),30);assert.equal(number(r.amounts.payment),0);assert.match(r.details.declaration,/Mantida/);r=calc(own({amount:'0'})).result;assert.equal(number(r.amounts.tax),0);assert.equal(calc(own({amount:''})).result.status,'indeterminate');r=calc(own({amount:'200000',priorInYear:'3900000',annual2026:'4100000'})).result;assert.equal(number(r.amounts.ordinary),100000);assert.equal(number(r.amounts.excess),100000);assert.equal(number(r.amounts.tax),25000);});
|
||||
test('documentedliberatory5meansno secondselftax;smallwithholdingnotminimum500;divergenceunknown',()=>{const p={settlement:'withheld',origin:'effective',buyerIspc:'yes',unregistered:'yes',buyerAnnualPurchases:'200000',withheldActual:'5000',withheldRef:'SYNTHETIC QA recibo5'};let r=calc(own(p)).result;assert.equal(r.status,'settled_by_withholding',r.missing.join(';'));assert.equal(number(r.amounts.withheld),5000);assert.equal(r.amounts.payment,undefined);assert.match(r.reason,/não somar nova liquidação/);r=calc(own({...p,amount:'100',withheldActual:'5'})).result;assert.equal(r.status,'settled_by_withholding');assert.equal(number(r.amounts.tax),5);assert.equal(calc(own({...p,withheldActual:'4000'})).result.status,'indeterminate');assert.equal(calc(own({...p,buyerAnnualPurchases:'2500000.000001'})).result.status,'indeterminate');});
|
||||
test('selfeffective requiresapplicableoption;forecastcannot masqueradeasactual;nonoptionnoISPC',()=>{assert.equal(calc(own({origin:'effective'})).result.status,'indeterminate');assert.equal(calc(own({option:'not_opted'})).result.status,'not_applicable');const r=calc(own({origin:'effective',operationDate:'2026-12-31',quarter:'4',option:'opted',optionRef:'QA opção',optionDate:'2026-01-01',annualOrigin:'closed_year'})).result;assert.equal(r.status,'calculated',r.missing.join(';'));assert.equal(calc(own({origin:'effective',option:'opted',optionRef:'QA',optionDate:'2026-07-01'})).result.status,'indeterminate');});
|
||||
test('above2.5m splits100kcovered/100kexcess;5kknownbuttotalnullwithunknownroute',()=>{const r=calc(acq()).result;assert.equal(r.status,'partial');assert.equal(number(r.amounts.covered),100000);assert.equal(number(r.amounts.coveredTax),5000);assert.equal(number(r.amounts.excess),100000);assert.equal(r.amounts.excessTax,null);assert.equal(r.amounts.total,null);});
|
||||
test('positiveIRPS57k20onidentifiedgrossact—separatefromISPCexcess20andownbuyerpayment',()=>{const p={route:'irps_isolated',noIspcOnExcess:'yes',isolatedAct:'yes',incomeInMoz:'yes',grossExcess:'100000',grossRef:'SYNTHETIC QA base ilíquida',reference:'SYNTHETIC QA8h/57k sem opção5'};const r=calc(acq(p)).result;assert.equal(r.status,'calculated',r.missing.join(';'));assert.equal(number(r.amounts.excessTax),20000);assert.equal(number(r.amounts.total),25000);assert.match(r.reason,/não são crédito/);for(const patch of [{grossExcess:''},{grossExcess:'80000'},{noIspcOnExcess:''},{isolatedAct:''},{incomeInMoz:'no'},{reference:''}]){const r=calc(acq({...p,...patch})).result;assert.equal(r.status,'partial');assert.equal(r.amounts.total,null);}});
|
||||
test('supplierISPCnotautomaticallyIRPS;crossingexactboundaryandprioroverlimit;noimplicit5onexcess',()=>{let r=calc(acq({route:'ispc_supplier',supplierOptionRef:'QA opção aplicável'})).result;assert.equal(r.status,'partial');assert.equal(r.amounts.excessTax,null);assert.match(r.reason,/art5impede/);r=calc(acq({}, {base:'100000'})).result;assert.equal(r.status,'not_applicable');assert.equal(number(r.amounts.excess),0);r=calc(acq({}, {priorAnnualPurchases:'2500001'})).result;assert.equal(number(r.amounts.covered),0);assert.equal(number(r.amounts.coveredTax),0);assert.equal(number(r.amounts.excess),200000);});
|
||||
test('newbooks preservehabitualandL3exactly;dependenciesstale withoutrewritingfrozenresults',()=>{let{d,b}=acq();const old=JSON.parse(d.modelo_a_snapshot);b=calc({d,b});d.modelo_a_snapshot=saveIspcResidualBook(d,b);for(const[k,v]of Object.entries(old))assert.deepEqual(JSON.parse(d.modelo_a_snapshot)[k],v);assert.equal(ispcResidualCurrent(d,b),true);const w=ispcWithholdingBook(d);w.input.base='300000';d.modelo_a_snapshot=saveIspcWithholdingBook(d,w);assert.equal(ispcResidualCurrent(d,b),false);assert.equal(number(b.result.amounts.excess),100000);const next=recordIspcResidual(d,b);assert.equal(next.history.length,1);assert.equal(number(next.result.amounts.excess),200000);assert.equal(number(next.history[0].amounts.excess),100000);});
|
||||
test('formalBGeneral mappingfromexistingcurrentquarterwithoutrecalculation;monthnotinferred;old30notused',()=>{const d=structuredClone(seed),b=ispcResidualBook(d,'formalities'),before=d.modelo_a_snapshot;const result=recordIspcResidual(d,b);assert.equal(result.result.status,'partial');assert.equal(number(result.result.amounts.tax),24000);assert.equal(number(result.result.amounts.payment),24000);assert.match(result.result.details.formPeriod,/Indeterminado/);assert.equal(result.result.details.paymentMonth,'Julho2026');assert.equal(result.input.formMonth,'');d.modelo_a_snapshot=saveIspcResidualBook(d,result);const html=ispcFormalPreparationHtml(d);assert.match(html,/24000.00/);assert.match(html,/Quadro8/);assert.match(html,/Quadro10/);assert.match(html,/não é formulário oficial/);assert.deepEqual(JSON.parse(d.modelo_a_snapshot).ispcQuarters,JSON.parse(before).ispcQuarters);});
|
||||
test('formalinputsguardedandexternalactsdeclaredonly;signed/officialareasnotautofilled;HTMLescaped',()=>{let d=structuredClone(seed),b=ispcResidualBook(d,'formalities');b.input={...b.input,name:'QA <script>bad()</script>',nuit:'123456789',fiscalArea:'QAUGC',address:'QAendereço',formMonth:'06',formYear:'2026',formPeriodRef:'SYNTHETIC QA correspondência período',interestSituation:'none',interestRef:'SYNTHETIC QA sem juros'};b=recordIspcResidual(d,b);assert.equal(b.result.status,'calculated',b.result.missing.join(';'));d.modelo_a_snapshot=saveIspcResidualBook(d,b);const html=ispcFormalPreparationHtml(d);assert.ok(html.includes('<script>'));assert.ok(!html.includes('<script>bad'));assert.match(html,/não preencher.*assinatura/i);b.input.externalStatus='paid';assert.equal(recordIspcResidual(d,b).result.status,'partial');});
|
||||
test('documentedwithholdingownroutepreventsduplicatedformalselfpayment',()=>{let{d,b}=own({settlement:'withheld',buyerIspc:'yes',unregistered:'yes',buyerAnnualPurchases:'200000',withheldActual:'5000',withheldRef:'QA recibo5'});b=recordIspcResidual(d,b);d.modelo_a_snapshot=saveIspcResidualBook(d,b);const f=ispcResidualBook(d,'formalities');f.input.sourceKind='occasional';const r=recordIspcResidual(d,f).result;assert.equal(r.status,'not_applicable');assert.match(r.reason,/duplicada/);});
|
||||
test('invalidstoredmaps/enumspreserveerrors;noemptyfallback',()=>{const d=structuredClone(seed),s=JSON.parse(d.modelo_a_snapshot);s.ispcResiduals=[];assert.throws(()=>ispcResidualBook({...d,modelo_a_snapshot:JSON.stringify(s)},'occasional'));const b=ispcResidualBook(d,'occasional');b.input.activity='services12';assert.throws(()=>saveIspcResidualBook(d,b));});
|
||||
test('exports separate seller376/buyer375 and report;habitualbooksunchanged',()=>{let{d,b}=own();d.context_opportunity='opportunity:376';d.person_type='singular';d.project_title='SYNTHETIC QA — ISPC residuais';const e=ispcEligibilityBook(d);e.input.mode='occasional';e.input.personType='singular';d.modelo_a_snapshot=saveIspcEligibilityBook(d,e);b=recordIspcResidual(d,b,'2026-10-25T15:40:00Z');d.modelo_a_snapshot=saveIspcResidualBook(d,b);d.context_opportunity='opportunity:375';d.person_type='collective';const a=acq({route:'irps_isolated',noIspcOnExcess:'yes',isolatedAct:'yes',incomeInMoz:'yes',grossExcess:'100000',grossRef:'QA base ilíquida',reference:'QA acto57k'});const aw=ispcWithholdingBook(a.d);d.modelo_a_snapshot=saveIspcWithholdingBook(d,aw);d.modelo_a_snapshot=saveIspcResidualBook(d,recordIspcResidual(d,a.b,'2026-10-25T15:41:00Z'));const f=ispcResidualBook(d,'formalities');d.modelo_a_snapshot=saveIspcResidualBook(d,recordIspcResidual(d,f,'2026-10-25T15:42:00Z'));const report=createProjectDossierReport(d,{selectedSections:new Set(['finance']),version:'QA residuais',generatedAt:'2026-10-25T15:43:00Z'});assert.match(JSON.stringify(report),/25000.00/);assert.match(JSON.stringify(report),/24000.00/);assert.match(JSON.stringify(ispcResidualReportRows(d)),/IRPS57/);d.context_opportunity='opportunity:376';assert.equal(ispcResidualBook(d,'occasional').result.status,'calculated');assert.equal(number(ispcResidualBook(d,'occasional').result.amounts.tax),3000);d.context_opportunity='opportunity:375';if(process.env.ISPC_RESIDUAL_OUTPUT)fs.writeFileSync(process.env.ISPC_RESIDUAL_OUTPUT,JSON.stringify(d,null,2));});
|
||||
|
||||
test('new uniqueformsource preserves deliberatechoice;documentedoptionwithannualforecast staysscenario',()=>{let{d,b}=own({origin:'effective',option:'opted',optionRef:'QA opção',optionDate:'2026-01-01'});b=recordIspcResidual(d,b);assert.equal(b.result.status,'calculated');assert.equal(b.result.details.projected,'yes');assert.match(b.result.reason,/Cenário declarado/);const e=ispcEligibilityBook(d);e.input.mode='occasional';d.modelo_a_snapshot=saveIspcEligibilityBook(d,e);d.modelo_a_snapshot=saveIspcResidualBook(d,b);let f=ispcResidualBook(d,'formalities');assert.equal(f.input.sourceKind,'occasional');f.input.sourceKind='quarter';d.modelo_a_snapshot=saveIspcResidualBook(d,f);assert.equal(ispcResidualBook(d,'formalities').input.sourceKind,'quarter');});
|
||||
|
||||
test('acquisitionformalpreparation distinguishesISPC5andIRPS20andkeepsspecificexternalmodelpending',()=>{let{d,b}=acq({route:'irps_isolated',noIspcOnExcess:'yes',isolatedAct:'yes',incomeInMoz:'yes',grossExcess:'100000',grossRef:'QA base ilíquida',reference:'QA57k'});b=recordIspcResidual(d,b);d.modelo_a_snapshot=saveIspcResidualBook(d,b);let f=ispcResidualBook(d,'formalities');f.input.sourceKind='acquisitions';f=recordIspcResidual(d,f);assert.equal(number(f.result.amounts.tax),25000);assert.ok(f.result.missing.some(s=>s.includes('Modelo/código')));assert.equal(f.result.status,'partial');d.modelo_a_snapshot=saveIspcResidualBook(d,f);const html=ispcFormalPreparationHtml(d);assert.match(html,/ISPC—retenção12/);assert.match(html,/IRPS—acto isolado57/);assert.match(html,/5000.00/);assert.match(html,/20000.00/);assert.match(html,/Por corresponder/);});
|
||||
|
||||
test('knownownaccess exclusions are concrete notrequestsforrevalidation;unknownstillindeterminate',()=>{for(const patch of [{organizedRequired:'yes'},{priorYearTurnover:'4000000.000001'}]){const r=calc(own(patch)).result;assert.equal(r.status,'not_applicable');assert.equal(r.amounts.payment,undefined);assert.match(r.reason,/fora/i);}assert.equal(calc(own({organizedRequired:''})).result.status,'indeterminate');});
|
||||
|
||||
test('below500paymentdispensa iscalculatedbutformalrepresentationnotinventedaszerocalculatedtax',()=>{let{d,b}=own({amount:'1000'});b=recordIspcResidual(d,b);d.modelo_a_snapshot=saveIspcResidualBook(d,b);let f=ispcResidualBook(d,'formalities');f.input={...f.input,sourceKind:'occasional',name:'QA vendedor',nuit:'123456789',fiscalArea:'QAUGC',address:'QA endereço',formMonth:'06',formYear:'2026',formPeriodRef:'QA correspondência',interestSituation:'none',interestRef:'QA sem juros'};f=recordIspcResidual(d,f);assert.equal(number(f.result.amounts.tax),30);assert.equal(number(f.result.amounts.payment),0);assert.equal(f.result.status,'partial');assert.ok(f.result.missing.some(s=>s.includes('dispensa')));d.modelo_a_snapshot=saveIspcResidualBook(d,f);const html=ispcFormalPreparationHtml(d);assert.match(html,/Imposto calculado:30.00;prestação legal:0.00/);});
|
||||
|
||||
test('switchfromdocumentedliberatoryroute cannotgenerate secondduewithoutconcretereconciliation',()=>{let{d,b}=own({settlement:'withheld',buyerIspc:'yes',unregistered:'yes',buyerAnnualPurchases:'200000',withheldActual:'5000',withheldRef:'QA retenção definitiva'});b=recordIspcResidual(d,b);assert.equal(b.result.status,'settled_by_withholding');b.input.settlement='self';let next=recordIspcResidual(d,b);assert.equal(next.result.status,'partial');assert.equal(next.result.amounts.payment,null);assert.equal(next.result.amounts.tax,null);assert.equal(number(next.result.amounts.withheld),5000);assert.equal(next.history[0].status,'settled_by_withholding');const fresh=structuredClone(b);fresh.input.reference='QA outra operação';assert.equal(recordIspcResidual(d,fresh).result.status,'calculated');b.input.withholdingCorrected='yes';b.input.withholdingCorrectionRef='QA documento externo de rectificação';next=recordIspcResidual(d,b);assert.equal(next.result.status,'calculated');assert.equal(number(next.result.amounts.payment),3000);assert.equal(next.result.details.priorWithholdingRef,'QA retenção definitiva');assert.equal(next.history[0].status,'settled_by_withholding');});
|
||||
@@ -0,0 +1,7 @@
|
||||
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
||||
import {ispcWithholdingBook,saveIspcWithholdingBook,recordIspcWithholding,ispcWithholdingReportRows} from '../../resources/js/lib/ispc-withholding.ts';
|
||||
const seed=JSON.parse(fs.readFileSync(new URL('./fixtures/ispc-quarter-preserved.json',import.meta.url),'utf8'));
|
||||
function evaluate(p={}){const d=structuredClone(seed),b=ispcWithholdingBook(d);b.input={...b.input,applicable:'yes',base:'10000',priorAnnualPurchases:'0',naturalOccasional:'yes',unregistered:'yes',related:'yes',activity:'agriculture',reference:'SYNTHETIC QA fornecedor e aquisição',...p};return{d,b,r:recordIspcWithholding(d,b)};}
|
||||
test('fivepercent withholding notownquartertax;small withholding notexempt via500minimum',()=>{let{r}=evaluate();assert.deepEqual(r.result.withheld,{numerator:'500',denominator:'1'});r=evaluate({base:'100'}).r;assert.deepEqual(r.result.withheld,{numerator:'5',denominator:'1'});});
|
||||
test('globalannual2.5minclusive,exceedingnottruncated;missingnotzero;scopeexclusionsspecific',()=>{assert.equal(evaluate({priorAnnualPurchases:'2490000'}).r.result.status,'calculated');assert.equal(evaluate({priorAnnualPurchases:'2490000.000001'}).r.result.status,'indeterminate');assert.equal(evaluate({priorAnnualPurchases:''}).r.result.status,'indeterminate');for(const p of [{naturalOccasional:'no'},{unregistered:'no'},{related:'no'},{activity:'other'},{applicable:'no'}])assert.equal(evaluate(p).r.result.status,'not_applicable');assert.equal(evaluate({naturalOccasional:''}).r.result.status,'indeterminate');});
|
||||
test('withholdingrecoverhistoryandotherbookspreserved;reportneveroffsetsowntax',()=>{let{d,r}=evaluate();const prior=JSON.parse(d.modelo_a_snapshot);d.modelo_a_snapshot=saveIspcWithholdingBook(d,r);assert.deepEqual(JSON.parse(d.modelo_a_snapshot).ispcQuarters,prior.ispcQuarters);const b=ispcWithholdingBook(d);assert.equal(b.result.status,'calculated');b.input.base='20000';r=recordIspcWithholding(d,b);assert.equal(r.history.length,1);assert.equal(r.history[0].withheld.numerator,'500');d.modelo_a_snapshot=saveIspcWithholdingBook(d,r);assert.match(JSON.stringify(ispcWithholdingReportRows(d)),/1000.00/);});
|
||||
Reference in New Issue
Block a user