Preserva classificacao contabilistica aceite e bases locais
Regista aceitacao funcional do primeiro incremento PGC-NIRF e preserva as dependencias documentais e tecnicas existentes. A validacao do calculo fiscal continua separada e pendente. Sem credenciais, bases operacionais ou publicacao.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import assert from 'node:assert/strict';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
const fixturePath = 'C:/laragon/data/sgf-tempo/secrets/browser-fixture.json';
|
||||
const fixture = JSON.parse(await fs.readFile(fixturePath, 'utf8'));
|
||||
const base = 'http://127.0.0.1:8001';
|
||||
function client() {
|
||||
const cookies = new Map(); let csrf = ''; let token = '';
|
||||
return {
|
||||
async request(path, method = 'GET', body, context = token) {
|
||||
const response = await fetch(base + path, { method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', Cookie: [...cookies].map(([k,v]) => `${k}=${v}`).join('; '), 'X-CSRF-TOKEN': csrf, 'X-SGF-Context': context, 'Idempotency-Key': randomUUID() }, ...(body === undefined ? {} : { body: JSON.stringify(body) }) });
|
||||
for (const cookie of response.headers.getSetCookie()) { const pair = cookie.split(';', 1)[0], split = pair.indexOf('='); cookies.set(pair.slice(0, split), pair.slice(split + 1)); }
|
||||
const data = await response.json().catch(() => ({})); if (data.csrf) csrf = data.csrf; if (data.context?.token) token = data.context.token;
|
||||
return { status: response.status, data };
|
||||
},
|
||||
async login(email) { await this.request('/api/session'); assert.equal((await this.request('/api/login', 'POST', { email, password: fixture.password })).status, 200); return this.select(); },
|
||||
async select(unit = fixture.unit, company = fixture.company) { const response = await this.request('/api/context', 'POST', { tenant_id: fixture.tenant, company_id: company, unit_id: unit }); assert.equal(response.status, 200); return response.data.context.token; }
|
||||
};
|
||||
}
|
||||
const manager = client(), reader = client(); await manager.login('gestor@example.test'); await reader.login('consulta@example.test');
|
||||
async function create(area, data) { const result = await manager.request('/api/a/' + area, 'POST', data); assert.equal(result.status, 201); return result.data.id; }
|
||||
async function save(kind, id, data) { const result = await manager.request(`/api/document-preparation/${kind}/${id}`, 'PATCH', data); assert.equal(result.status, 200); return result.data; }
|
||||
const customer = await create('clients', { name: 'Cliente documental de demonstração' });
|
||||
const service = await create('services', { name: 'Serviço documental de demonstração' });
|
||||
const source = await create('service_drafts', { client_id: customer, lines: [{ service_id: service, quantity: '1.25', unit_price: '0.00000001' }] });
|
||||
const oldDraft = await create('billing_drafts', { source_id: source, name: 'B1 anterior à preparação documental' });
|
||||
assert.equal((await manager.request(`/api/b1/billing-drafts/${oldDraft}/confirm-internal`, 'POST', { version: 1 })).status, 200);
|
||||
const oldBefore = (await manager.request(`/api/a/billing_drafts/${oldDraft}`)).data.confirmation;
|
||||
assert.equal(oldBefore.snapshot.schema_version, undefined);
|
||||
const profile = { version: 0, nuit: 'IDENTIFICAÇÃO SINTÉTICA', address: 'Morada sintética', locality: 'Localidade de teste', country: 'País de teste' };
|
||||
await save('issuer', fixture.company, profile); await save('client', customer, profile);
|
||||
const privateMarker = 'SYNTHETIC-' + randomUUID();
|
||||
const paymentData = { version: 0, label: 'Instruções de demonstração — sem operação bancária', bank: 'Banco fictício de teste', holder: 'Titular sintético', account_number: privateMarker, instructions: 'Apenas instruções sintéticas; não efectuar pagamentos.', currency: null };
|
||||
const instruction = (await save('payment', 0, paymentData)).id;
|
||||
const preparation = { version: 0, draft_version: 1, currency: null, service_date: '2026-11-01', period_start: '2026-11-01', period_end: '2026-11-30', payment_terms: 'Prazo a conferir com vencimento; sem regra aprovada', proposed_due_date: '2026-11-15', price_mode: 'undefined', units: ['hora'], payment_instruction_ids: [instruction] };
|
||||
await save('service_drafts', source, preparation);
|
||||
const newDraft = await create('billing_drafts', { source_id: source, name: 'Documento interno com preparação versão 2' });
|
||||
const reused = (await manager.request(`/api/document-preparation/billing_drafts/${newDraft}`)).data;
|
||||
assert.equal(reused.data.units[0], 'hora'); assert.equal(reused.data.payment_instruction_ids[0], instruction); assert.equal(reused.currency, null);
|
||||
assert.equal((await manager.request(`/api/b1/billing-drafts/${newDraft}/confirm-internal`, 'POST', { version: 1 })).status, 200);
|
||||
const snapshot = (await manager.request(`/api/a/billing_drafts/${newDraft}`)).data.confirmation;
|
||||
assert.equal(snapshot.snapshot.schema_version, 2); assert.equal(snapshot.snapshot.document_preparation.payment_instructions[0].data.account_number, privateMarker);
|
||||
await save('payment', instruction, { ...paymentData, version: 1, instructions: 'Instruções sintéticas revistas após confirmação.' });
|
||||
assert.deepEqual((await manager.request(`/api/a/billing_drafts/${oldDraft}`)).data.confirmation, oldBefore);
|
||||
assert.deepEqual((await manager.request(`/api/a/billing_drafts/${newDraft}`)).data.confirmation, snapshot);
|
||||
assert.equal((await reader.request(`/api/document-preparation/payment/${instruction}`)).status, 200);
|
||||
assert.equal((await reader.request(`/api/document-preparation/payment/${instruction}`, 'PATCH', { ...paymentData, version: 2 })).status, 403);
|
||||
assert.equal((await manager.request(`/api/document-preparation/payment/${instruction}`, 'PATCH', { ...paymentData, version: 1 })).status, 409);
|
||||
const oldContext = await manager.select(); await manager.select(null);
|
||||
assert.equal((await manager.request(`/api/document-preparation/issuer/${fixture.company}`, 'PATCH', { ...profile, version: 1 }, oldContext)).status, 409);
|
||||
await manager.select(null, fixture.sibling);
|
||||
assert.equal((await manager.request(`/api/document-preparation/payment/${instruction}`)).status, 403);
|
||||
await manager.select();
|
||||
const editableDraft = await create('billing_drafts', { source_id: source, name: 'Percurso visual — preparação documental' });
|
||||
fixture.document_client_id = customer; fixture.document_source_id = source; fixture.document_draft_id = editableDraft;
|
||||
await fs.writeFile(fixturePath, JSON.stringify(fixture));
|
||||
await manager.request('/api/logout', 'POST'); await reader.request('/api/logout', 'POST');
|
||||
await fs.writeFile('docs/proofs/document-http-results.json', JSON.stringify({ database: 'sgf_tempo_test', real_synthetic_login: true, results: ['Client created with name only; company/client profiles reused.', 'Source preparation and selected issuer instruction reused in billing draft.', 'Existing B1 v1 and future v2 snapshots unchanged after configuration updates.', 'Reader can consult instructions; editing denied 403.', 'Old version/context denied 409; other company denied 403.', 'Currency unknown, exact prices unchanged; no receipt, issue or accounting operation.'], instruction_values: 'omitted' }, null, 2));
|
||||
console.log('Isolated document preparation HTTP proof passed. Instruction values omitted.');
|
||||
Reference in New Issue
Block a user