315 lines
11 KiB
JavaScript
315 lines
11 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import fs from 'node:fs';
|
||
import {
|
||
newCommissionBase,
|
||
switchCommissionDirection,
|
||
commissionBaseTreatments,
|
||
commissionBaseConditions,
|
||
evaluateCommissionBase,
|
||
recordCommissionBases,
|
||
saveCommissionBaseBook,
|
||
commissionBaseBook,
|
||
commissionBaseCurrent,
|
||
commissionBaseReportRows,
|
||
} from '../../resources/js/lib/iva-commission-base.ts';
|
||
import { publicBaseCurrent } from '../../resources/js/lib/iva-public-authority-base.ts';
|
||
import { importExemptionCurrent } from '../../resources/js/lib/iva-import-exemptions.ts';
|
||
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
|
||
const frozen = JSON.parse(
|
||
fs.readFileSync(
|
||
new URL('./fixtures/iva-g7b-preserved-inputs.json', import.meta.url),
|
||
'utf8',
|
||
),
|
||
);
|
||
const row = (treatment = commissionBaseTreatments[0].id) => ({
|
||
...newCommissionBase('g7b-' + treatment, 'MZN'),
|
||
treatment,
|
||
description: 'SYNTHETIC QA bens transferidos em comissão',
|
||
period: '2026-12',
|
||
principal: 'SYNTHETIC QA comitente',
|
||
agent: 'SYNTHETIC QA comissário',
|
||
agreementRef: 'SYNTHETIC QA contrato A,comissão desta operação',
|
||
agreedPrice: '1000.25',
|
||
priceRef: 'SYNTHETIC QA preço acordado pelo comissário antes do ajuste',
|
||
commissionAmount: '100.10',
|
||
commissionRef: 'SYNTHETIC QA comissão contratada em valor,semIVA',
|
||
compositionRef:
|
||
'SYNTHETIC QA composição15(5)/(6),valores líquidos e sem ajuste anterior',
|
||
documentRef: 'SYNTHETIC QA G7B ' + treatment,
|
||
documentDate: '2026-11-14',
|
||
evidence:
|
||
'SYNTHETIC QA pressupostos expressos,bens/contrato/sentido/próprias condições,não documento real',
|
||
conditions: Object.fromEntries(
|
||
commissionBaseConditions.map(([key]) => [key, 'yes']),
|
||
),
|
||
});
|
||
const draft = () => ({
|
||
...structuredClone(frozen),
|
||
context_opportunity: 'opportunity:340',
|
||
project_title: 'SYNTHETIC QA — G7B / Bases de comissão',
|
||
});
|
||
|
||
void test('P091 own goods/contract/direction/composition conditions and references;unknown/no never become tax or base zero', () => {
|
||
for (const rule of commissionBaseTreatments) {
|
||
const input = row(rule.id),
|
||
ok = evaluateCommissionBase(input, 'MZN');
|
||
assert.equal(ok.status, 'determined');
|
||
assert.equal(
|
||
ok.baseAmount,
|
||
rule.id === 'commission_sale_transfer' ? '900.15' : '1100.35',
|
||
);
|
||
assert.equal(ok.vat, null);
|
||
assert.equal(ok.rate, null);
|
||
for (const [key] of commissionBaseConditions)
|
||
for (const value of ['', 'unknown', 'no']) {
|
||
const r = evaluateCommissionBase(
|
||
{
|
||
...input,
|
||
conditions: { ...input.conditions, [key]: value },
|
||
},
|
||
'MZN',
|
||
);
|
||
assert.equal(
|
||
r.status,
|
||
value === 'no' ? 'not_applicable' : 'indeterminate',
|
||
);
|
||
assert.equal(r.baseAmount, null);
|
||
assert.equal(r.vat, null);
|
||
}
|
||
for (const patch of [
|
||
{ principal: '' },
|
||
{ agent: '' },
|
||
{ agreementRef: '' },
|
||
{ priceRef: '' },
|
||
{ commissionRef: '' },
|
||
{ compositionRef: '' },
|
||
{ documentRef: '' },
|
||
{ documentDate: '2026-02-30' },
|
||
{ period: '2025-12' },
|
||
{ currency: 'USD' },
|
||
])
|
||
assert.equal(
|
||
evaluateCommissionBase({ ...input, ...patch }, 'MZN')
|
||
.baseAmount,
|
||
null,
|
||
);
|
||
}
|
||
});
|
||
|
||
void test('sale subtracts and purchase adds exact commission once;explicitzero differs fromunknown and negative difference is not floored', () => {
|
||
const input = row();
|
||
for (const [patch, expected] of [
|
||
[{ agreedPrice: '0', commissionAmount: '0' }, '0.00'],
|
||
[{ agreedPrice: '1.000002', commissionAmount: '0.000001' }, '1.000001'],
|
||
[
|
||
{
|
||
treatment: 'commission_purchase_transfer',
|
||
agreedPrice: '999999999999999.999999',
|
||
commissionAmount: '999999999999999.999999',
|
||
},
|
||
'1999999999999999.999998',
|
||
],
|
||
])
|
||
assert.equal(
|
||
evaluateCommissionBase({ ...input, ...patch }, 'MZN').baseAmount,
|
||
expected,
|
||
);
|
||
for (const patch of [
|
||
{ commissionAmount: '' },
|
||
{ agreedPrice: '' },
|
||
{ agreedPrice: '-1' },
|
||
{ commissionAmount: 'NaN' },
|
||
{ commissionAmount: '0.0000001' },
|
||
])
|
||
assert.equal(
|
||
evaluateCommissionBase({ ...input, ...patch }, 'MZN').baseAmount,
|
||
null,
|
||
);
|
||
const negative = evaluateCommissionBase(
|
||
{ ...input, agreedPrice: '50', commissionAmount: '100' },
|
||
'MZN',
|
||
);
|
||
assert.equal(negative.baseAmount, null);
|
||
assert.match(negative.reason, /−50.00/);
|
||
assert.equal(negative.vat, null);
|
||
assert.equal(
|
||
evaluateCommissionBase(
|
||
{
|
||
...input,
|
||
treatment: 'commission_purchase_transfer',
|
||
agreedPrice: '50',
|
||
commissionAmount: '100',
|
||
},
|
||
'MZN',
|
||
).baseAmount,
|
||
'150.00',
|
||
);
|
||
const switched = switchCommissionDirection(
|
||
input,
|
||
'commission_purchase_transfer',
|
||
);
|
||
assert.equal(switched.conditions.directionConfirmed, '');
|
||
assert.equal(switched.agreedPrice, input.agreedPrice);
|
||
assert.equal(switched.priceRef, input.priceRef);
|
||
assert.equal(switched.commissionAmount, input.commissionAmount);
|
||
assert.equal(switched.principal, input.principal);
|
||
assert.equal(evaluateCommissionBase(switched, 'MZN').baseAmount, null);
|
||
assert.equal(
|
||
evaluateCommissionBase(
|
||
{
|
||
...switched,
|
||
conditions: {
|
||
...switched.conditions,
|
||
directionConfirmed: 'yes',
|
||
},
|
||
},
|
||
'MZN',
|
||
).baseAmount,
|
||
'1100.35',
|
||
);
|
||
});
|
||
|
||
void test('P091 save/recovery/history/report preserve all79 delivered books including P090/P060/P084P085 and old currentkeys', () => {
|
||
const d = draft(),
|
||
prior = JSON.parse(d.modelo_a_snapshot);
|
||
assert.deepEqual(commissionBaseBook(d), { rows: [] });
|
||
assert.deepEqual(commissionBaseReportRows(d), []);
|
||
let book = recordCommissionBases(d, {
|
||
rows: commissionBaseTreatments.map((rule) => ({
|
||
...row(rule.id),
|
||
conditions: {},
|
||
})),
|
||
});
|
||
book = recordCommissionBases(d, {
|
||
...book,
|
||
rows: commissionBaseTreatments.map((rule) => ({
|
||
...row(rule.id),
|
||
conditions: {
|
||
...row(rule.id).conditions,
|
||
commissionContract: 'no',
|
||
},
|
||
})),
|
||
});
|
||
book = recordCommissionBases(d, {
|
||
...book,
|
||
rows: commissionBaseTreatments.map((rule) => row(rule.id)),
|
||
});
|
||
assert.equal(book.history.length, 2);
|
||
assert.ok(
|
||
book.history.every((h) =>
|
||
h.rows.every((r) => r.baseAmount === null && r.vat === null),
|
||
),
|
||
);
|
||
assert.ok(commissionBaseCurrent(d, book));
|
||
for (const field of [
|
||
'treatment',
|
||
'agreedPrice',
|
||
'commissionAmount',
|
||
'priceRef',
|
||
'commissionRef',
|
||
'agreementRef',
|
||
'principal',
|
||
])
|
||
assert.ok(
|
||
!commissionBaseCurrent(d, {
|
||
...book,
|
||
rows: book.rows.map((r) => ({ ...r, [field]: 'changed' })),
|
||
}),
|
||
);
|
||
for (const patch of [
|
||
{ context_opportunity: 'opportunity:341' },
|
||
{ currency: 'USD' },
|
||
{ selection_labels: { province_id: 'Maputo' } },
|
||
])
|
||
assert.ok(!commissionBaseCurrent({ ...d, ...patch }, book));
|
||
d.modelo_a_snapshot = saveCommissionBaseBook(d, book);
|
||
assert.deepEqual(commissionBaseBook(JSON.parse(JSON.stringify(d))), book);
|
||
const next = JSON.parse(d.modelo_a_snapshot);
|
||
const { commissionBases: _commissionBases, ...untouched } = next;
|
||
assert.deepEqual(untouched, prior);
|
||
for (const [scope, previous] of Object.entries(prior.importExemptions))
|
||
assert.ok(
|
||
importExemptionCurrent(
|
||
{ ...d, context_opportunity: scope },
|
||
previous,
|
||
),
|
||
);
|
||
for (const [scope, previous] of Object.entries(prior.publicAuthorityBases))
|
||
assert.ok(
|
||
publicBaseCurrent({ ...d, context_opportunity: scope }, previous),
|
||
);
|
||
assert.equal(
|
||
next.publicAuthorityBases['opportunity:339'].result.rows[0].vat,
|
||
null,
|
||
);
|
||
assert.equal(
|
||
next.importExemptions['opportunity:338'].result.rows[1].importVat,
|
||
'400.00',
|
||
);
|
||
assert.equal(
|
||
next.books['opportunity:329'].result.periods[0].fields['11'],
|
||
null,
|
||
);
|
||
const report = JSON.stringify(
|
||
createProjectDossierReport(d, {
|
||
selectedSections: new Set(['finance']),
|
||
version: 'QA G7B',
|
||
}),
|
||
);
|
||
for (const token of [
|
||
'Base P091',
|
||
'900.15',
|
||
'1100.35',
|
||
'IVA: Indeterminado',
|
||
'opportunity:340',
|
||
'Manica',
|
||
'2026-12',
|
||
'contrato A',
|
||
'15(2)(e)',
|
||
'100.10',
|
||
'campo11',
|
||
])
|
||
assert.ok(report.includes(token), token);
|
||
assert.deepEqual(
|
||
commissionBaseReportRows({
|
||
...d,
|
||
context_opportunity: 'opportunity:341',
|
||
}),
|
||
[],
|
||
);
|
||
if (process.env.IVA_G7B_CALCULATED)
|
||
fs.writeFileSync(process.env.IVA_G7B_CALCULATED, JSON.stringify(d));
|
||
});
|
||
|
||
void test('corrupt commission rows/store cannot overwrite originals;duplicate operation identifiers cannot be calculated', () => {
|
||
const d = draft(),
|
||
original = d.modelo_a_snapshot;
|
||
for (const patch of [
|
||
{ commissionAmount: 4 },
|
||
{ conditions: [] },
|
||
{ priceRef: null },
|
||
])
|
||
assert.throws(
|
||
() => saveCommissionBaseBook(d, { rows: [{ ...row(), ...patch }] }),
|
||
/originais preservados/,
|
||
);
|
||
assert.equal(d.modelo_a_snapshot, original);
|
||
assert.throws(
|
||
() => recordCommissionBases(d, { rows: [row(), row()] }),
|
||
/distintos/,
|
||
);
|
||
assert.throws(() => recordCommissionBases(d, { rows: [] }), /distintos/);
|
||
assert.throws(
|
||
() =>
|
||
commissionBaseBook({
|
||
...d,
|
||
modelo_a_snapshot: JSON.stringify({
|
||
...JSON.parse(original),
|
||
commissionBases: [],
|
||
}),
|
||
}),
|
||
/originais preservados/,
|
||
);
|
||
});
|