367 lines
12 KiB
JavaScript
367 lines
12 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
newRemission,
|
|
remissionConditions,
|
|
evaluateRemission,
|
|
ippItems,
|
|
ippAuthority,
|
|
diplomaticRoles,
|
|
recordRemissions,
|
|
saveRemissionBook,
|
|
remissionBook,
|
|
remissionCurrent,
|
|
remissionReportRows,
|
|
} from '../../resources/js/lib/iva-remission-imports.ts';
|
|
import '../../resources/js/lib/iva-objective-imports.ts';
|
|
const frozen = JSON.parse(
|
|
fs.readFileSync(
|
|
'tests/frontend/fixtures/iva-remission-preserved.json',
|
|
'utf8',
|
|
),
|
|
),
|
|
prior = JSON.parse(frozen.modelo_a_snapshot),
|
|
draft = {
|
|
...frozen,
|
|
context_opportunity: 'opportunity:367',
|
|
project_title: 'SYNTHETIC QA — P047 quatro famílias',
|
|
};
|
|
function row(family, id, patch = {}) {
|
|
const r = {
|
|
...newRemission(id ?? family, 'MZN'),
|
|
family,
|
|
description: 'SYNTHETIC QA bens ' + (id ?? family),
|
|
importer: 'SYNTHETIC QA importador ' + (id ?? family),
|
|
period: '2026-10',
|
|
importDate: '2026-10-15',
|
|
scope: 'SYNTHETIC QA bens/operação/período/condições',
|
|
evidence: 'SYNTHETIC QA pressupostos expressos',
|
|
documentRef: 'SYNTHETIC QA documentos',
|
|
rights: 'exempt',
|
|
rightsRef: 'SYNTHETIC QA isenção de direitos:fundamento e âmbito',
|
|
decision: 'planned',
|
|
decisionRef: 'SYNTHETIC QA deferimento previsto neste âmbito',
|
|
decisionDate: '2026-10-01',
|
|
requestRef: 'SYNTHETIC QA requerimento prévio',
|
|
specialRef:
|
|
'SYNTHETIC QA cláusula,condições específicas/compromisso de uso',
|
|
ippItem: '3',
|
|
patronagePath: 'book',
|
|
role: 'agent',
|
|
quantity: '1',
|
|
existingQuantity: '0',
|
|
limit: '2',
|
|
limitRef: 'SYNTHETIC QA reciprocidade e limite',
|
|
history: 'none',
|
|
historyRef: 'SYNTHETIC QA histórico externo',
|
|
agreementRef: 'SYNTHETIC QA acordo e cláusula',
|
|
...patch,
|
|
};
|
|
r.conditions = Object.fromEntries(
|
|
remissionConditions(r).map(([k]) => [k, 'yes']),
|
|
);
|
|
return r;
|
|
}
|
|
const examples = [];
|
|
void test('P047 partido: equipamento próprio; sem quota diplomática nem nova aprovação', () => {
|
|
const r = row('party', 'party', {
|
|
decision: 'not_required',
|
|
decisionRef: '',
|
|
requestRef: '',
|
|
specialRef: '',
|
|
limit: '',
|
|
historyRef: '',
|
|
});
|
|
assert.equal(evaluateRemission(r, 'MZN').status, 'exempt');
|
|
for (const k of ['equipment', 'nonBusiness', 'party'])
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, conditions: { ...r.conditions, [k]: 'no' } },
|
|
'MZN',
|
|
).status,
|
|
'not_applicable',
|
|
);
|
|
examples.push(r);
|
|
});
|
|
for (const path of ['book', 'donation', 'specific'])
|
|
void test('P047 mecenato / ' + path, () => {
|
|
const r = row('patronage', 'patronage-' + path, {
|
|
patronagePath: path,
|
|
decision: path === 'donation' ? 'planned' : 'not_required',
|
|
});
|
|
const v = evaluateRemission(r, 'MZN');
|
|
assert.equal(v.status, 'exempt');
|
|
assert.equal(v.importVat, '0.00');
|
|
assert.equal(v.deduction, null);
|
|
assert.equal(
|
|
remissionConditions(r).some(([k]) => k === 'confirmation'),
|
|
path === 'donation',
|
|
);
|
|
examples.push(r);
|
|
});
|
|
for (const [role] of diplomaticRoles)
|
|
void test('P047 categoria diplomática / ' + role, () => {
|
|
const r = row('diplomatic', 'diplomatic-' + role, {
|
|
role,
|
|
limit:
|
|
role === 'mission'
|
|
? '8'
|
|
: role === 'head'
|
|
? '3'
|
|
: ['honorary', 'technical'].includes(role)
|
|
? '1'
|
|
: '2',
|
|
});
|
|
assert.equal(evaluateRemission(r, 'MZN').status, 'exempt');
|
|
assert.equal(
|
|
remissionConditions(r).some(([k]) => k === 'foreignNonResident'),
|
|
['agent', 'technical'].includes(role),
|
|
);
|
|
examples.push(r);
|
|
});
|
|
for (const item of ippItems)
|
|
void test('P047 IPP22 / ' + item.id, () => {
|
|
const r = row('ipp', 'ipp-' + item.id, { ippItem: item.id });
|
|
assert.equal(evaluateRemission(r, 'MZN').status, 'exempt');
|
|
assert.match(
|
|
evaluateRemission(r, 'MZN').source,
|
|
new RegExp('item' + item.id + ';'),
|
|
);
|
|
examples.push(r);
|
|
});
|
|
void test('P047 IPP lista exemplificada não substitui condições; outro artigo exige citação', () => {
|
|
const r = row('ipp', 'ipp-specific', {
|
|
ippItem: 'specific',
|
|
ippArticle: 'SYNTHETIC QA artigo específico e versão',
|
|
});
|
|
assert.equal(evaluateRemission(r, 'MZN').status, 'exempt');
|
|
assert.equal(
|
|
evaluateRemission({ ...r, ippArticle: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission({ ...r, specialRef: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission({ ...r, requestRef: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, conditions: { ...r.conditions, ownConditions: '' } },
|
|
'MZN',
|
|
).status,
|
|
'indeterminate',
|
|
);
|
|
examples.push(r);
|
|
});
|
|
void test('P047 IPP competência não retroage2026; taxa0 não é isenção; encargo do Estado não basta', () => {
|
|
assert.match(ippAuthority('3', '2026-07-30'), /Director Regional/);
|
|
assert.match(ippAuthority('3', '2026-07-31'), /Director-Geral/);
|
|
assert.match(ippAuthority('30', '2026-07-30'), /por identificar/);
|
|
assert.match(
|
|
evaluateRemission(
|
|
row('ipp', 'old-authority', {
|
|
ippItem: '3',
|
|
decisionDate: '2026-07-30',
|
|
}),
|
|
'MZN',
|
|
).source,
|
|
/Director Regional/,
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
row('ipp', 'missing-date', { decisionDate: '' }),
|
|
'MZN',
|
|
).status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
row('ipp', 'early30', {
|
|
ippItem: '30',
|
|
period: '2026-07',
|
|
importDate: '2026-07-30',
|
|
decisionDate: '2026-07-30',
|
|
}),
|
|
'MZN',
|
|
).status,
|
|
'indeterminate',
|
|
);
|
|
for (const item of ['28', '30'])
|
|
for (const rights of ['zero', 'none', 'reduced'])
|
|
assert.equal(
|
|
evaluateRemission(
|
|
row('ipp', item, { ippItem: item, rights }),
|
|
'MZN',
|
|
).status,
|
|
'not_applicable',
|
|
);
|
|
});
|
|
void test('P047 pedido apresentado nunca concede; previsto apenas projecção; âmbito exacto', () => {
|
|
for (const family of ['party', 'patronage', 'diplomatic', 'ipp']) {
|
|
const r = row(family);
|
|
assert.equal(
|
|
evaluateRemission({ ...r, decision: 'requested' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission({ ...r, decision: 'denied' }, 'MZN').status,
|
|
'not_applicable',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission({ ...r, origin: 'effective' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, origin: 'effective', decision: 'approved' },
|
|
'MZN',
|
|
).status,
|
|
'exempt',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, decisionRef: '', decision: 'approved' },
|
|
'MZN',
|
|
).status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, conditions: { ...r.conditions, scope: 'no' } },
|
|
'MZN',
|
|
).status,
|
|
'not_applicable',
|
|
);
|
|
}
|
|
});
|
|
void test('P047 desconhecido/fonte ausente/data impossível não viram IVAzero', () => {
|
|
const r = row('party');
|
|
for (const patch of [
|
|
{ rights: '' },
|
|
{ rightsRef: '' },
|
|
{ scope: '' },
|
|
{ documentRef: '' },
|
|
{ importer: '' },
|
|
{ importDate: '2026-02-30' },
|
|
{ period: '2027-10' },
|
|
{ currency: 'USD' },
|
|
{ conditions: { ...r.conditions, equipment: '' } },
|
|
]) {
|
|
const v = evaluateRemission({ ...r, ...patch }, 'MZN');
|
|
assert.equal(v.status, 'indeterminate');
|
|
assert.equal(v.importVat, null);
|
|
}
|
|
assert.equal(
|
|
evaluateRemission({ ...r, rights: 'zero' }, 'MZN').status,
|
|
'not_applicable',
|
|
);
|
|
});
|
|
void test('P047 veículos: quotas e reciprocidade inferiores,5anos,desconhecido; sem extensão de agentes a agências', () => {
|
|
const r = row('diplomatic');
|
|
for (const patch of [
|
|
{ quantity: '3' },
|
|
{ quantity: '2', existingQuantity: '1' },
|
|
{ quantity: '2', limit: '1' },
|
|
])
|
|
assert.equal(
|
|
evaluateRemission({ ...r, ...patch }, 'MZN').status,
|
|
'not_applicable',
|
|
);
|
|
for (const patch of [
|
|
{ history: '' },
|
|
{ limit: '' },
|
|
{ history: 'known', previousDate: '2021-10-16' },
|
|
{ limitRef: '' },
|
|
{ quantity: '1.5' },
|
|
{ quantity: '-1' },
|
|
])
|
|
assert.equal(
|
|
evaluateRemission({ ...r, ...patch }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateRemission(
|
|
{ ...r, history: 'known', previousDate: '2021-10-15' },
|
|
'MZN',
|
|
).status,
|
|
'exempt',
|
|
);
|
|
const agency = row('diplomatic', 'agency', {
|
|
role: 'agency',
|
|
limit: '',
|
|
history: '',
|
|
historyRef: '',
|
|
quantity: '',
|
|
existingQuantity: '',
|
|
});
|
|
assert.equal(evaluateRemission(agency, 'MZN').status, 'exempt');
|
|
assert.equal(
|
|
evaluateRemission({ ...agency, agreementRef: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
});
|
|
void test('P047 veículos:duas linhas do mesmo direito não duplicam limite nem janela5anos', () => {
|
|
const a = row('diplomatic', 'a', { quantity: '2' }),
|
|
b = { ...a, id: 'b' };
|
|
assert.deepEqual(
|
|
recordRemissions(draft, { rows: [a, b] }).result.rows.map(
|
|
(r) => r.status,
|
|
),
|
|
['indeterminate', 'indeterminate'],
|
|
);
|
|
const c = { ...b, quantity: '1', importDate: '2026-10-16' };
|
|
assert.deepEqual(
|
|
recordRemissions(draft, {
|
|
rows: [{ ...a, quantity: '1' }, c],
|
|
}).result.rows.map((r) => r.status),
|
|
['indeterminate', 'indeterminate'],
|
|
);
|
|
});
|
|
void test('P047 recuperação/histórico/relatório preservam128fechos e quatro percursosQA P058', () => {
|
|
let book = recordRemissions(draft, { rows: examples });
|
|
assert.equal(examples.length, 42);
|
|
assert.equal(remissionCurrent(draft, book), true);
|
|
const old = structuredClone(book.result);
|
|
book = {
|
|
...book,
|
|
rows: book.rows.map((r, i) =>
|
|
i ? r : { ...r, scope: 'SYNTHETIC QA novo âmbito' },
|
|
),
|
|
};
|
|
assert.equal(remissionCurrent(draft, book), false);
|
|
assert.deepEqual(book.result, old);
|
|
book = recordRemissions(draft, book);
|
|
assert.deepEqual(book.history[0], old);
|
|
draft.modelo_a_snapshot = saveRemissionBook(draft, book);
|
|
assert.deepEqual(remissionBook(draft), book);
|
|
const after = JSON.parse(draft.modelo_a_snapshot);
|
|
for (const [k, v] of Object.entries(prior)) assert.deepEqual(after[k], v);
|
|
assert.equal(
|
|
remissionBook({ ...draft, context_opportunity: 'opportunity:999' }).rows
|
|
.length,
|
|
0,
|
|
);
|
|
assert.match(remissionReportRows(draft)[0][3], /versão2/);
|
|
assert.match(remissionReportRows(draft)[0][2], /IVA:0.00/);
|
|
assert.throws(
|
|
() =>
|
|
saveRemissionBook(draft, {
|
|
rows: [{ ...examples[0], rightsRef: { bad: true } }],
|
|
}),
|
|
/não recuperáveis/,
|
|
);
|
|
assert.throws(
|
|
() => recordRemissions(draft, { rows: [examples[0], examples[0]] }),
|
|
/distintas/,
|
|
);
|
|
if (process.env.IVA_REMISSION_FIXTURE)
|
|
fs.writeFileSync(
|
|
'tests/frontend/fixtures/iva-remission.json',
|
|
JSON.stringify(draft),
|
|
);
|
|
});
|