Files
SGF/scripts/sgf-multiline-invoice-ui.mjs
2026-11-11 15:04:01 +02:00

12 lines
11 KiB
JavaScript

process.on('uncaughtException',e=>{console.error(String(e.stack??e).replace(/data:text\/javascript;base64,[A-Za-z0-9+/=]+/g,'compiled-ui'));process.exit(1);});
import fs from'node:fs';import assert from'node:assert/strict';import{pathToFileURL}from'node:url';import{transformWithOxc}from'vite';const root=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')).root+'/private/receipt-composition-cc50a276c10c',checks=[],ok=(v,n)=>{assert(v,n);checks.push(n);};let slots=[],cursor=0,effects=[],tree,calls=[],rootComponent,props;const same=(a,b)=>a&&b&&a.length===b.length&&a.every((v,i)=>v===b[i]);const R={createElement:(type,props,...children)=>({type,props:props??{},children}),Fragment:Symbol('fragment'),Suspense:Symbol('suspense'),lazy:()=>Symbol('lazy'),useRef(initial){const i=cursor++;slots[i]??={value:{current:initial}};return slots[i].value;},useState(initial){const i=cursor++;slots[i]??={value:typeof initial==='function'?initial():initial};return[slots[i].value,v=>{slots[i].value=typeof v==='function'?v(slots[i].value):v;}];},useMemo(fn,deps){const i=cursor++;if(!same(slots[i]?.deps,deps))slots[i]={value:fn(),deps};return slots[i].value;},useEffect(fn,deps){const i=cursor++;if(!same(slots[i]?.deps,deps)){slots[i]?.cleanup?.();slots[i]={deps};effects.push(()=>slots[i].cleanup=fn());}}};globalThis.__hrHooks=R;const stub='const r=globalThis.__hrHooks;export default r;export const useState=r.useState,useMemo=r.useMemo,useEffect=r.useEffect,useRef=r.useRef;',reactUrl='data:text/javascript;base64,'+Buffer.from(stub).toString('base64'),compile=async(file,imports)=>{let s=fs.readFileSync('resources/js/'+file,'utf8').replace(/from\s*['"]react['"]/, 'from '+JSON.stringify(reactUrl));for(const f of imports)s=s.replace(new RegExp('from\\s*[\'"]\\./'+f.replaceAll('.','\\.')+'[\'"]'),'from '+JSON.stringify(pathToFileURL(process.cwd()+'/resources/js/'+f).href));const c=await transformWithOxc(s,file,{jsx:{runtime:'classic'}});return import('data:text/javascript;base64,'+Buffer.from(c.code).toString('base64'));};
const{default:Workspace,InvoiceReferencePicker,InvoiceTotals,checkedInvoiceOptions}=await compile('MultiLineInvoiceWorkspace.jsx',['workshop-stock-operation.js']);const{navigationGroups}=await compile('WorkspaceNavigation.jsx',['billing-menu.js','workshop-menu.js','stock-menu.js','accounting-menu.js']);const{moduleGroups}=await compile('ModuleNavigation.jsx',[]);
const result={base_document:'1000.00',tax_document:'160.00',total:'1160.00',price_mode:'net_added',lines:[1,2].map(line=>({line,base_document:line===1?'400.00':'600.00',tax_document:line===1?'64.00':'96.00',total_document:line===1?'464.00':'696.00',base_exact_fraction:line===1?'400':'600',tax_exact_fraction:line===1?'64':'96',base_difference_fraction:'0',tax_difference_fraction:'0'}))};let fail=true,posted=[],calcDone=false,temporalDone=false,reviewDone=false,issued=false;const frame=()=>({policy:'SGF-MULTI-LINE-INVOICE-INTEGRATED-QA-v1',server_date:'2026-11-11',billing:{id:57,name:'QA-UI-MULTI',version:1,client_id:1,data:{client_name:'Cliente fictício UI',currency:'MZN',lines:[{service_id:1,service_name:'QA-SERVICE',quantity:'1',unit_price:'400'},{service_id:1,service_name:'QA-SERVICE',quantity:'1',unit_price:'600'}]}},source:{id:7,version:1},preparation:{version:1,data:{price_mode:'added',period_start:'2026-11-01',period_end:'2026-11-30',units:['UN','UN']}},parties:{},invoice:issued?{id:5,series_code:'TEST-MULTI-2026',number:1,totals:result}:null});const temporal=()=>({id:3,identifier:'MULTI-DRAFT-57',version:1,actor_id:8,data:{},decision:reviewDone?{decision:'approved',actor_id:9}:null});
const api=async(path,method,body,token,key)=>{calls.push({path,method,body,key});if(method==='POST'){if(path.endsWith('/preview'))return path.includes('/drafts/')?{preview:'draft-cut',impact:{after:{name:body.name,client:'Cliente fictício UI',lines:body.lines,arithmetic_amount:'1000'}}}:{preview:'calculation-cut',impact:{result}};if(path.endsWith('/readiness'))return{ready:true,review_hash:'a'.repeat(64),payload:{document:{client:{name:'Cliente fictício UI'}},series_code:'TEST-MULTI-2026',expected_date:'2026-11-11',calculation_entry:{snapshot:{result:{common_document_result:result}}}}};posted.push({path,body:structuredClone(body),key});if(path.endsWith('/drafts/confirm')){if(fail){const e=Error('Resultado incerto503');e.status=503;throw e;}return{id:57,source_id:7,version:1,source_version:1,preparation_version:1,type:'draft'};}if(path.endsWith('/calculations/confirm')){calcDone=true;return{id:2,draft_id:57,rule_event_id:12,draft_version:1,preparation_version:1,type:'calculation',result};}if(path.endsWith('/decision')){reviewDone=true;return{id:3,decision:'approved'};}if(path.endsWith('/temporals')){temporalDone=true;return{id:3,version:1};}if(path.endsWith('/issue')){issued=true;return{id:5,number:1,series_code:'TEST-MULTI-2026'};}}if(path.includes('/drafts/57'))return frame();const q=new URL('http://qa'+path).searchParams,kind=q.get('kind');return{kind,records:{current_page:Number(q.get('page')),per_page:Number(q.get('per_page')),total:1,last_page:1,data:kind==='drafts'?[{id:57,name:'QA-UI-MULTI',version:1}]:kind==='calculations'&&calcDone?[{id:2,rule_event_id:12,draft_id:57,draft_version:1,preparation_version:1,result,date:'2026-11-11'}]:kind==='temporals'&&temporalDone?[temporal()]:[]}};};
const render=()=>{cursor=0;tree=rootComponent(props);const jobs=effects;effects=[];jobs.forEach(f=>f());return tree;},tick=async()=>{await new Promise(r=>setTimeout(r,0));render();},descend=n=>Array.isArray(n)?n.flatMap(descend):n&&typeof n==='object'?[n,...descend(n.children)]:[],nodes=(n=tree)=>descend(n),text=n=>Array.isArray(n)?n.map(text).join(''):n&&typeof n==='object'?text(n.children):String(n??''),find=(tag,label)=>nodes().find(n=>n.type===tag&&text(n).includes(label));
rootComponent=Workspace;props={api,context:{token:'mi-qa',unit:{id:2},company:{id:2}},actor:8,can:()=>true,navigate:()=>{},markClean:()=>{}};render();await tick();ok(calls.length===1&&calls[0].path.includes('kind=drafts'),'bounded initial list only no implicit source choice');ok(!find('h2','Cálculo e conferência temporal'),'no first document automatically opened');let pick=nodes().find(n=>n.type===InvoiceReferencePicker&&n.props.kind==='clients');pick.props.onChange('1',{name:'Cliente fictício UI'});render();const field=(label,value,index=0)=>{const n=nodes().filter(n=>n.type==='label'&&text(n).startsWith(label))[index];n.children.find(c=>['input','textarea','select'].includes(c?.type)).props.onChange({target:{value}});render();};field('Designação','Documento UI de duas linhas');field('Modalidade de preço','added');field('Período desde','2026-11-01');field('Período até','2026-11-30');pick=nodes().find(n=>n.type===InvoiceReferencePicker&&n.props.kind==='services');pick.props.onChange('1',{name:'QA-SERVICE'});render();field('Quantidade','1');field('Preço sem imposto','400');field('Unidade','UN');find('button','Adicionar linha').props.onClick();render();pick=nodes().filter(n=>n.type===InvoiceReferencePicker&&n.props.kind==='services')[1];ok(pick.props.value==='','second service explicitly unselected');pick.props.onChange('1',{name:'QA-SERVICE'});render();field('Quantidade','1',1);field('Preço sem imposto','600',1);field('Unidade','UN',1);field('Fundamento da preparação','Fundamento individual de duas linhas UI');ok(nodes().find(n=>n.props?.['data-sgf-operation-uncertain']==='true'),'dirty form protects context transitions');const form=nodes().find(n=>n.type==='form'&&text(n).includes('Cabeçalho'));await form.props.onSubmit({preventDefault(){}});render();const preview=calls.find(c=>c.path.endsWith('/drafts/preview'));ok(preview.body.lines.length===2&&preview.body.lines[0].unit_price==='400'&&preview.body.lines[1].unit_price==='600','draft preview has both exact price strings');ok(Boolean(find('h2','Impacto antes da confirmação'))&&find('button','Novo documento').props.disabled,'impact locks changing document');await find('button','Confirmar este impacto').props.onClick();render();ok(Boolean(find('h2','Resultado por recuperar'))&&find('button','Novo documento').props.disabled,'uncertain failure preserves operation and blocks replacement');fail=false;await find('button','Recuperar a mesma operação').props.onClick();render();await tick();ok(posted.length===2&&JSON.stringify(posted[0])===JSON.stringify(posted[1]),'same path body and key recover without replacement');ok(Boolean(find('h2','Cálculo e conferência temporal'))&&!find('h2','Resultado por recuperar'),'saved draft opens same header and lines');pick=nodes().find(n=>n.type===InvoiceReferencePicker&&n.props.kind==='rules');ok(pick.props.value==='','rule never automatically chosen');pick.props.onChange('12');render();field('Fundamento fiscal/documental','Conferência explícita das duas linhas UI');await find('button','Conferir cálculo destas linhas').props.onClick();render();ok(calls.at(-1).body.rule_event_id===12&&calls.at(-1).body.draft_id===57,'calculation bound to chosen rule and exact draft');await find('button','Confirmar este impacto').props.onClick();render();await tick();ok(nodes().some(n=>n.type===InvoiceTotals&&n.props.result?.total==='1160.00'),'selected current calculation supplies visible total');await find('button','Preparar regra temporal desta origem').props.onClick();render();await tick();ok(!find('button','Aprovar versão temporal'),'preparer not offered own approval');props.actor=9;render();field('Fundamento independente','Fundamento independente da prontidão UI');await find('button','Aprovar versão temporal').props.onClick();render();await tick();pick=nodes().find(n=>n.type===InvoiceReferencePicker&&n.props.kind==='series');ok(pick.props.value==='','series explicitly unselected');pick.props.onChange('4');render();await find('button','Conferir prontidão e impacto de emissão').props.onClick();render();ok(Boolean(find('button','Confirmar emissão só de teste'))&&!posted.some(p=>p.path.endsWith('/issue')),'readiness assigns no invoice or number');await find('button','Confirmar emissão só de teste').props.onClick();render();await tick();ok(posted.filter(p=>p.path.endsWith('/issue')).length===1&&find('a','Descarregar o PDF preservado').props.href==='/api/service-invoices/5/pdf','one emission and exact frozen PDF link');ok(nodes().some(n=>n.type===InvoiceTotals&&n.props.result?.total==='1160.00'),'issued photograph keeps totals visible after reload');const unknown=InvoiceTotals({result:null});ok(text(unknown).includes('A conferir')&&!text(unknown).includes('0 MZN'),'unknown tax never shown as zero');const groups=navigationGroups(r=>r==='billing_drafts.view',2,{multilineInvoices:true});ok(moduleGroups(groups,'commercial').some(g=>g.items.some(i=>i.id==='multiline_invoices')),'own commercial dropdown entry');ok(!groups.some(g=>g.id==='accounting'),'document right grants no accounting functions');assert.throws(()=>checkedInvoiceOptions({kind:'series',records:{current_page:1,per_page:25,data:[]}},'calculations',1,25));ok(true,'wrong catalogue kind response refused');const file=root+'/multiline-invoice-ui-20261111.json';fs.writeFileSync(file,JSON.stringify({passed:true,checks,api_mocked:true,browser_visual_review:false},null,2));console.log(JSON.stringify({passed:true,checks:checks.length,proof:file}));