177 lines
7.0 KiB
JavaScript
177 lines
7.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { fiscalQaRows } from "../../resources/js/lib/fiscal-qa-preview.ts";
|
|
import { exportCompletedArithmeticCsv, readArithmeticSnapshot } from "../../resources/js/lib/simulation-form.ts";
|
|
import { createProjectDossierReport } from "../../resources/js/lib/project-dossier-report.ts";
|
|
|
|
function fixture() {
|
|
const snapshot = {
|
|
contract_version: 1,
|
|
scenario_kind: "fiscal_rule_qa_preview",
|
|
base: "0.03",
|
|
currency: "MZN",
|
|
indicative_total: "0.0048",
|
|
legal_interpretation: false,
|
|
formula_version: "investmoz.tax.v1",
|
|
context: {
|
|
reference_date: "2026-10-21",
|
|
currency: "MZN",
|
|
currency_fraction_digits: 2,
|
|
scenario_id: "61000100-0000-4000-8000-000000000099",
|
|
scenario_version: 1,
|
|
engine_version: "fiscal-draft-preview-v1",
|
|
ruleset_version: "IVA-GERAL-BASE-LIQUIDA:1",
|
|
},
|
|
result: {
|
|
status: "calculated",
|
|
value: "0.0048",
|
|
unit: "MZN",
|
|
explanation:
|
|
"Cálculo exacto QA; enquadramento declarado; não é saldo a pagar.",
|
|
missing_inputs: [],
|
|
source_ids: ["source-fixture"],
|
|
},
|
|
intermediate: { result: "48/10000" },
|
|
fiscal_provenance: {
|
|
rule: {
|
|
rule_code: "IVA-GERAL-BASE-LIQUIDA",
|
|
rule_version: 1,
|
|
valid_from: "2023-01-01",
|
|
valid_until: null,
|
|
source_sha256: "a".repeat(64),
|
|
source: { diploma: "Lei 22/2022", article: "Artigo 17(1)" },
|
|
},
|
|
},
|
|
};
|
|
return {
|
|
id: "61000100-0000-4000-8000-000000000088",
|
|
status: "completed",
|
|
version_no: 2,
|
|
result_snapshot: snapshot,
|
|
reports: [
|
|
{
|
|
id: "61000100-0000-4000-8000-000000000077",
|
|
version_no: 1,
|
|
status: "ready",
|
|
report_snapshot: structuredClone(snapshot),
|
|
report_sha256: "b".repeat(64),
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
test("screen rows preserve sub-cent IVA as a string and distinguish calculation from payment", () => {
|
|
const simulation = fixture();
|
|
const before = JSON.stringify(simulation);
|
|
const rows = fiscalQaRows(simulation.result_snapshot);
|
|
assert.equal(
|
|
rows.find(([label]) => label.startsWith("IVA calculado"))[1],
|
|
"0.0048",
|
|
);
|
|
assert.match(
|
|
rows.find(([label]) => label === "Arredondamento")[1],
|
|
/Não aplicado/,
|
|
);
|
|
assert.match(
|
|
rows.find(([label]) => label === "Enquadramento")[1],
|
|
/não validado juridicamente/,
|
|
);
|
|
assert.equal(JSON.stringify(simulation), before);
|
|
});
|
|
|
|
test("CSV preserves the exact amount and refuses a mismatched immutable report", () => {
|
|
const simulation = fixture();
|
|
const csv = exportCompletedArithmeticCsv(
|
|
simulation,
|
|
"2026-10-21T09:00:00Z",
|
|
);
|
|
assert.match(csv, /0\.0048/);
|
|
assert.doesNotMatch(csv, /Resultado fiscal final,Indeterminado/);
|
|
simulation.reports[0].report_snapshot.result.value = "0.00";
|
|
assert.throws(
|
|
() => exportCompletedArithmeticCsv(simulation),
|
|
/relatório preservado/,
|
|
);
|
|
});
|
|
|
|
test("dossier report uses the same exact snapshot and preserves genuine indetermination", () => {
|
|
const simulation = fixture();
|
|
function report() {
|
|
return createProjectDossierReport(
|
|
{ project_title: "QA fiscal", currency: "MZN" },
|
|
{
|
|
selectedSections: new Set(["finance"]),
|
|
currentCalculation: {
|
|
status: "completed",
|
|
version: 2,
|
|
snapshot: simulation.result_snapshot,
|
|
},
|
|
},
|
|
);
|
|
}
|
|
const rows = report().sections.find(
|
|
(section) => section.id === "finance",
|
|
).rows;
|
|
assert.equal(
|
|
rows.find((row) => row.field.startsWith("IVA calculado")).value,
|
|
"0.0048",
|
|
);
|
|
assert.equal(
|
|
rows.find((row) => row.field === "Fonte da taxa").value,
|
|
"Lei 22/2022 — Artigo 17(1)",
|
|
);
|
|
simulation.result_snapshot.result.status = "indeterminate";
|
|
simulation.result_snapshot.result.value = null;
|
|
simulation.result_snapshot.indicative_total = null;
|
|
simulation.result_snapshot.result.missing_inputs = ["eligible_parameter"];
|
|
assert.equal(
|
|
report()
|
|
.sections.find((section) => section.id === "finance")
|
|
.rows.find((row) => row.field.startsWith("IVA calculado")).value,
|
|
"Indeterminado",
|
|
);
|
|
});
|
|
|
|
test("published consumer routes the frozen snapshot through screen CSV and dossier without QA labels", () => {
|
|
const simulation = fixture();
|
|
const snapshot = simulation.result_snapshot;
|
|
snapshot.scenario_kind = "fiscal_rule_published";
|
|
snapshot.context.engine_version = "fiscal-published-v1";
|
|
snapshot.presentation = { value: snapshot.result.value, rounding_applied: false };
|
|
snapshot.result.explanation = "IVA pela versão publicada; enquadramento declarado.";
|
|
snapshot.fiscal_provenance.rule.status = "published";
|
|
snapshot.fiscal_provenance.scope_status = "user_declared";
|
|
snapshot.fiscal_provenance.mode = "published_version";
|
|
simulation.reports[0].report_snapshot = structuredClone(snapshot);
|
|
const before = JSON.stringify(simulation);
|
|
const rows = fiscalQaRows(snapshot);
|
|
assert.equal(readArithmeticSnapshot(snapshot).integrity, "versioned");
|
|
assert.match(rows[0][1], /publicada/);
|
|
assert.doesNotMatch(JSON.stringify(rows), /rascunho|não publicada|QA/);
|
|
const csv = exportCompletedArithmeticCsv(simulation, "2026-10-21T12:00:00Z");
|
|
for (const [label, value] of rows) {
|
|
assert.ok(csv.includes(label));
|
|
assert.ok(csv.includes(value.replaceAll('"', '""')));
|
|
}
|
|
const report = createProjectDossierReport({ project_title: "Published IVA QA", currency: "MZN" }, {
|
|
selectedSections: new Set(["finance"]), currentCalculation: { status: "completed", version: 2, snapshot },
|
|
});
|
|
const finance = report.sections.find((section) => section.id === "finance");
|
|
for (const [field, value] of rows) assert.ok(finance.rows.some((row) => row.field === field && row.value === value));
|
|
assert.doesNotMatch(JSON.stringify(finance), /rascunho|proveniência QA/);
|
|
assert.equal(JSON.stringify(simulation), before);
|
|
});
|
|
|
|
test("published consumer indeterminate snapshot is valid and a mismatched presentation is refused", () => {
|
|
const snapshot = fixture().result_snapshot;
|
|
snapshot.scenario_kind = "fiscal_rule_published";
|
|
snapshot.result.status = "indeterminate";
|
|
snapshot.result.value = null;
|
|
snapshot.result.missing_inputs = ["operation_scope"];
|
|
snapshot.indicative_total = null;
|
|
snapshot.presentation = { value: null, rounding_applied: false };
|
|
assert.equal(readArithmeticSnapshot(snapshot).integrity, "versioned");
|
|
snapshot.presentation.value = "0";
|
|
assert.equal(readArithmeticSnapshot(snapshot).integrity, "invalid");
|
|
});
|