Files
SGF/resources/js/ledger-report-view.js
2026-11-11 09:00:17 +02:00

28 lines
3.4 KiB
JavaScript

export function minorAmount(value){
if((typeof value==='number'&&!Number.isSafeInteger(value))||!/^[-]?\d+$/.test(String(value)))throw Error('Montante sem representação inteira exacta.');
const n=BigInt(value),a=n<0n?-n:n;return`${n<0n?'-':''}${a/100n},${String(a%100n).padStart(2,'0')}`;
}
export function ledgerReportQuery(form,page=1){
if(!/^\d{4}-\d{2}-\d{2}$/.test(form.from_on)||!/^\d{4}-\d{2}-\d{2}$/.test(form.to_on)||form.from_on>form.to_on)throw Error('Escolha um intervalo de datas válido e explícito.');
if(!['trial-balance','account-ledger'].includes(form.kind)||!['25','100'].includes(String(form.per_page)))throw Error('Consulta ou paginação inválida.');
if(form.account_id&&(!/^[1-9]\d*$/.test(String(form.account_id))||!Number.isSafeInteger(Number(form.account_id))))throw Error('Indique um identificador de conta válido.');
if(form.kind==='account-ledger'&&!form.account_id)throw Error('Escolha uma conta no balancete ou indique o seu identificador.');
return{kind:form.kind,params:{from_on:form.from_on,to_on:form.to_on,per_page:String(form.per_page),page,...(form.account_id?{account_id:Number(form.account_id)}:{})}};
}
export function reportBasis(data){return JSON.stringify(data.basis);}
export function checkedReport(data,query,expectedBasis=null){
const kind=query.kind==='trial-balance'?'trial_balance':'account_ledger';
if(data.kind!==kind||!data.synthetic_only||data.currency!=='MZN'||!Array.isArray(data.rows)||data.rows.length>Number(query.params.per_page)||data.query.from_on!==query.params.from_on||data.query.to_on!==query.params.to_on||data.pagination.page!==query.params.page||String(data.query.account_id??'')!==String(query.params.account_id??''))throw Error('A resposta não corresponde ao relatório e aos filtros pedidos.');
if(data.basis?.kind!=='append_only_snapshot_marker'||!Number.isSafeInteger(data.basis.journals)||!Number.isSafeInteger(data.basis.last_journal_id)||data.basis.through_on!==query.params.to_on)throw Error('Referência do livro indisponível.');
for(const [k,v]of Object.entries(data.totals??{}))if(k.endsWith('_minor'))minorAmount(v);
if(expectedBasis!==null&&reportBasis(data)!==expectedBasis)throw Error('O livro mudou entre páginas. Actualize a primeira página e confira novamente.');
for(const row of data.rows)for(const key of data.kind==='trial_balance'?['opening_net_minor','debit_minor','credit_minor','closing_net_minor']:['debit_minor','credit_minor','balance_minor'])minorAmount(row[key]);
return data;
}
const csvCell=v=>'"'+String(v??'').replaceAll('"','""')+'"';
export function reportPageCsv(data){
const trial=data.kind==='trial_balance',header=trial?['Conta','Designacao','Moeda','Abertura liquida','Debito','Credito','Fecho liquido']:['Lancamento','Linha','Data','Fundamento','Debito','Credito','Saldo progressivo'];
const rows=data.rows.map(r=>trial?["'"+r.code,"'"+r.label,r.currency,minorAmount(r.opening_net_minor),minorAmount(r.debit_minor),minorAmount(r.credit_minor),minorAmount(r.closing_net_minor)]:[r.journal_id,r.line_id,r.journal_on,"'"+r.reason,minorAmount(r.debit_minor),minorAmount(r.credit_minor),minorAmount(r.balance_minor)]);
return [['RELATORIO INTERNO QA — SEM VALIDADE FISCAL'],['Apenas a pagina consultada',data.pagination.page,'de',data.pagination.last_page],['De',data.query.from_on,'ate',data.query.to_on],['Moeda',data.currency],['Referencia do livro',JSON.stringify(data.basis)],header,...rows].map(row=>row.map(csvCell).join(';')).join('\r\n')+'\r\n';
}