Files
SGF/scripts/sgf-single-stock-final-http.mjs
2026-11-11 09:00:17 +02:00

21 lines
7.0 KiB
JavaScript

import fs from'node:fs';import assert from'node:assert/strict';import{session}from'./sgf-single-http.mjs';
const run=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')),root=run.root+'/private/receipt-composition-cc50a276c10c',file=root+'/single-stock-final-http-progress.json',progress=fs.existsSync(file)?JSON.parse(fs.readFileSync(file)):{operations:{},checks:[]};const save=()=>fs.writeFileSync(file,JSON.stringify(progress,null,2));
const clients={warehouse:await session('purchasing:validator','stock'),review:await session('sgf:workshop_verify','stock'),prepare:await session('sgf:accounting_prepare','accounting'),accountReview:await session('sgf:accounting_review','accounting')};
const state=async role=>{const r=await clients[role].get('/api/stock-final');assert.equal(r.status,200);return r.json();};let current=await state('warehouse');const p=current.policy;
const step=async(name,role,action,data)=>{let op=progress.operations[name];if(!op){op=progress.operations[name]={role,action,data,key:crypto.randomUUID()};save();}assert.deepEqual({role,action,data},{role:op.role,action:op.action,data:op.data});if(op.result)return op.result;
let r=await clients[role].get('/api/stock-final/receipts/'+op.key);if(r.status===200){const recovered=await r.json();op.result=recovered.result;save();return op.result;}assert.equal(r.status,404,'recover historical command before retrying');
const s=await state(role);r=await clients[role].command('/api/stock-final/preview',{action,data,operation_key:op.key,revision:s.revision,reason:'Decisão individual QA integrada8085: '+name+'.'});assert.equal(r.status,200,name+' preview '+JSON.stringify(r.value));op.impact=r.value.impact;save();r=await clients[role].command('/api/stock-final/confirm',{preview:r.value.preview});assert.equal(r.status,201,name+' confirm '+JSON.stringify(r.value));op.result=r.value;save();return r.value;};
const ledger=async(name,role,path,body)=>{let op=progress.operations[name];if(!op){op=progress.operations[name]={role,path,body,key:crypto.randomUUID()};save();}assert.deepEqual({role,path,body},{role:op.role,path:op.path,body:op.body});if(op.result)return op.result;const r=await clients[role].command(path,body,op.key);assert.equal(r.status,200,name+': '+JSON.stringify(r.value));op.result=r.value;save();return r.value;};
let r=await clients.warehouse.get('/stock/final',{headers:{Accept:'text/html'}});assert.equal(r.status,200);assert.match(await r.text(),/sgf-stock-final.mjs/);
progress.transferKey??=crypto.randomUUID();save();const transfer={stock_item_id:p.transfer_item_id,source_warehouse_id:p.source_warehouse_id,destination_warehouse_id:p.destination_warehouse_id,quantity:'1.000',transfer_key:progress.transferKey};
const dispatched=await step('expedir-1UN','warehouse','dispatch',transfer);assert.equal(dispatched.impact.ownership_change_milli,0);await step('receber-0.4UN','review','receive',{...transfer,quantity:'0.400'});await step('receber-0.6UN','review','receive',{...transfer,quantity:'0.600'});
const setup=await step('preparar-lotes','warehouse','prepare',{version:0,data:{stock_item_id:p.lot_item_id,warehouse_id:p.source_warehouse_id,requires_expiry:true,minimum_remaining_days:0,lots:[{code:'QA-8085-LOTE-A',expires_on:'2027-12-31',quantity:'2.000'},{code:'QA-8085-LOTE-B',expires_on:'2027-12-31',quantity:'2.000'}]}});
await step('activar-lotes','review','activate',{record_key:setup.record_key,version:setup.version,data:{}});current=await state('warehouse');progress.initialLots??=current.basis.lot_context.lots.map(l=>({id:l.id,record_key:l.record_key,version:l.version}));save();
for(const l of progress.initialLots){current=await state('review');const live=current.basis.lot_context.lots.find(v=>v.id===l.id);const name='libertar-lote-'+l.id;if(!progress.operations[name]){progress.releaseVersions??={};progress.releaseVersions[l.id]=live.state_version;save();}await step(name,'review','release',{record_key:l.record_key,version:l.version,data:{lot_id:l.id,warehouse_id:p.source_warehouse_id,state_version:progress.releaseVersions[l.id]}});}
current=await state('warehouse');progress.countBasis??={ledger_version:current.basis.lot_balance.version,lot_version:current.lot_count_source.hash,lot_counts:progress.initialLots.map((l,i)=>({lot_id:l.id,quantity:i===0?'1.500':'2.000'}))};save();const counted=await step('contar-3.5UN','warehouse','count',{quantity:'3.500',...progress.countBasis});
await step('rever-diferenca-0.5UN','review','adjustment',{quantity:'0.000',ledger_version:progress.countBasis.ledger_version,count_id:counted.operation_id});
r=await clients.prepare.get('/api/general-ledger');assert.equal(r.status,200);let data=await r.json();const book=data.stock.find(s=>s.book.stock_item_id===p.lot_item_id);assert(book);const rate=await ledger('taxa20','prepare','/api/general-ledger/stock/rate-prepare',{book_id:book.book.id,version:0,unit_minor:2000,reason:'Taxa sintética20MZN por UN para o artigo de lotes integrado.'});await ledger('rever-taxa20','accountReview','/api/general-ledger/stock/rate-review',{rate_id:rate.rate_id,version:1,decision:'approved',reason:'Conferência independente do artigo, unidade e taxa20.'});
for(const row of book.rows){const movement=row.movement,kind={receipt_in:'stock.receipt',adjustment_out:'stock.adjustment'}[movement.movement_type];assert(kind);const name=kind+'-'+movement.id;const proposal=await ledger(name+'-preparar','prepare','/api/general-ledger/effect-prepare',{effect_type:kind,source_id:movement.id,journal_on:'2026-11-10',period_key:'QA-2026-INTEGRADO',rule_key:kind,reason:'Valorização da origem física individual de lotes: '+kind+'.'});await ledger(name+'-rever','accountReview','/api/general-ledger/validate',{proposal_id:proposal.proposal_id,revision:proposal.revision,decision:'approved',reason:'Revisão distinta da origem, contagem e taxa20MZN.'});await ledger(name+'-aplicar','prepare','/api/general-ledger/post',{proposal_id:proposal.proposal_id,revision:proposal.revision,reason:'Aplicar uma única vez a valorização QA revista.'});}
r=await clients.prepare.get('/api/general-ledger');assert.equal(r.status,200);data=await r.json();assert.equal(data.journals.length,18);assert.equal(data.chart_accounts.length,15);assert.equal(data.totals.debit_minor,data.totals.credit_minor);const original=data.stock.find(s=>s.book.stock_item_id===p.transfer_item_id),lotBook=data.stock.find(s=>s.book.stock_item_id===p.lot_item_id);assert.equal(original.physical_balance_milli,500);assert(original.rows.some(row=>row.nonfinancial_reconciliation?.journal_required===false));assert.equal(lotBook.physical_balance_milli,3500);
current=await state('warehouse');assert.equal(current.basis.transfer_destination.quantity,1000);assert.equal(current.in_transit_milli,0);assert.deepEqual(current.basis.lot_context.lots.map(l=>l.quantity_milli),[1500,2000]);progress.passed=true;progress.journals=18;progress.stock={owned_original_milli:1500,original_minor:7500,lot_milli:3500,lot_minor:7000,total_minor:14500};save();console.log(JSON.stringify({passed:true,journals:18,proof:file,browser_visual_review:false}));