Files
SGF/scripts/receipt-composition-run.mjs
2026-11-04 09:37:20 +02:00

28 lines
12 KiB
JavaScript

import fs from 'node:fs';import path from 'node:path';import crypto from 'node:crypto';import {spawnSync} from 'node:child_process';
const repo=process.cwd(),source=path.resolve('../compras'),state=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json'));
if(state.port!==55439||!/^[a-f0-9]{12}$/.test(state.id)||path.resolve(state.root)!==path.resolve('C:/laragon/data/sgf-tempo/run/modular-regression-'+state.id))throw Error('Owned QA cluster required');
const php='C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe',psql='C:/Program Files/PostgreSQL/17/bin/psql.exe',tag=crypto.randomBytes(6).toString('hex'),root=path.join(state.root,'private/receipt-composition-'+tag),app=path.join(root,'app'),bundle=path.join(root,'bundle'),hostDb='budget_core_sgf_'+tag,hostRole='ir_composition_'+tag,nativeDb='compras_receipts_test_'+tag,nativeRole='payable_history_native_'+tag;
fs.mkdirSync(root);const hostPassword=crypto.randomBytes(32).toString('hex'),nativePassword=crypto.randomBytes(32).toString('hex'),admin=fs.readFileSync(path.join(state.root,'private/admin-password.txt'),'utf8').trim();
const pg=input=>{const r=spawnSync(psql,['-h','127.0.0.1','-p','55439','-U','sgf_regression_owner','-d','postgres','-Atq','-v','ON_ERROR_STOP=1'],{input,encoding:'utf8',windowsHide:true,env:{...process.env,PGPASSWORD:admin}});if(r.status!==0)throw Error('Private QA provisioning failed');return r.stdout.trim();};
if(pg("SELECT current_setting('cluster_name')")!=='sgf_modular_regression_'+state.id)throw Error('Wrong physical cluster');
for(const [db,role,password]of [[hostDb,hostRole,hostPassword],[nativeDb,nativeRole,nativePassword]])pg(`CREATE ROLE ${role} LOGIN PASSWORD '${password}' NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS; CREATE DATABASE ${db} OWNER ${role}; REVOKE ALL ON DATABASE ${db} FROM PUBLIC;`);
const storage=path.join(root,'native-storage');for(const d of ['framework/cache/data','framework/views','framework/sessions','logs','cache'])fs.mkdirSync(path.join(storage,d),{recursive:true});
const stockPeriod=process.argv.includes('stock-period'),stockTrace=process.argv.includes('stock-trace')||stockPeriod,stockComposition=process.argv.includes('stock-composition')||stockTrace,obligationEvidence=process.argv.includes('obligation-evidence')||stockComposition,invoiceProgress=process.argv.includes('invoice-progress')||obligationEvidence,requestHistory=process.argv.includes('request-history')||invoiceProgress,continuity=process.argv.includes('continuity')||requestHistory,focus=process.argv.includes('focus')||continuity,receiptDocuments=process.argv.includes('receipt-documents')||focus,supplierDocuments=process.argv.includes('supplier-documents')||receiptDocuments,receiptWorkspace=process.argv.includes('receipt-workspace')||supplierDocuments,dossiers=process.argv.includes('dossiers')||receiptWorkspace,supplierSearch=process.argv.includes('supplier-search'),integrated=process.argv.includes('integrated')||supplierSearch||dossiers,obligations=process.argv.includes('obligations')||integrated,invoices=process.argv.includes('invoices')||obligations,geography=process.argv.includes('geography')||integrated,requests=process.argv.includes('requests')||geography,suppliers=process.argv.includes('suppliers')||requests,sourcing=process.argv.includes('sourcing')||suppliers;const nativeSettings={stockPeriod,stockTrace,stockComposition,obligationEvidence,invoiceProgress,requestHistory,continuity,focus,receiptDocuments,supplierDocuments,receiptWorkspace,dossiers,supplierSearch,integrated,obligations,invoices,requests,suppliers,sourcing,tag,root,database:nativeDb,role:nativeRole,password:nativePassword,storage,native:source,ledger:path.resolve('packages/general-ledger'),run:state.id,app_key:'base64:'+crypto.randomBytes(32).toString('base64')};fs.writeFileSync(path.join(root,'settings.json'),JSON.stringify(nativeSettings,null,2));
function run(args,cwd=repo,env=process.env,log='step'){const r=spawnSync(php,args,{cwd,env,encoding:'utf8',windowsHide:true,timeout:180000,maxBuffer:2*1024*1024});fs.writeFileSync(path.join(root,log+'.log'),r.stdout+'\n'+r.stderr);if(r.status!==0)throw Error(log+' failed; private diagnostics preserved for '+tag);}
const orders=process.argv.includes('orders')||sourcing||invoices;run(['scripts/stock-ledger-entry.php',path.join(root,'settings.json'),orders?'order-native-setup':'receipt-native-setup'],repo,process.env,'native-setup');if(invoices&&!integrated)run(['scripts/stock-ledger-entry.php',path.join(root,'settings.json'),'invoice-native-negative'],repo,process.env,'invoice-negative');
if(geography||invoices){const ref=path.join(state.root,'private/receipt-composition-297f4626f01f');for(const name of ['bundle','economic','internal'])fs.cpSync(path.join(ref,name),path.join(root,name),{recursive:true});}else run(['scripts/build-receipt-runtime.php',source,bundle],repo,process.env,'namespace-bundle');if(orders&&!geography&&!invoices){const economic=path.join(root,'economic'),files={};fs.mkdirSync(economic);for(const file of ['ProposalScoring.php','QuotationPricing.php']){const bytes=fs.readFileSync(path.join(source,'packages/purchasing/src',file));fs.writeFileSync(path.join(economic,file),bytes);files[file]=crypto.createHash('sha256').update(bytes).digest('hex');}fs.writeFileSync(path.join(economic,'manifest.json'),JSON.stringify({files},null,2));}
if(requests&&!geography&&!invoices){const internal=path.join(root,'internal'),files={};fs.mkdirSync(internal);for(const file of ['RequisitionPort.php','RequisitionFailure.php','InternalRequisitions.php']){const bytes=fs.readFileSync(path.join(source,'packages/purchasing/src',file));fs.writeFileSync(path.join(internal,file),bytes);files[file]=crypto.createHash('sha256').update(bytes).digest('hex');}fs.writeFileSync(path.join(internal,'manifest.json'),JSON.stringify({files},null,2));}
for(const dir of ['app','bootstrap','config','routes','resources','database','public'])fs.cpSync(dir,path.join(app,dir),{recursive:true,filter:p=>!p.replaceAll('\\','/').includes('bootstrap/cache')});
for(const pkg of ['budget-control','payables','general-ledger','module-updates','purchasing','inventory-read'])fs.cpSync(path.join('packages',pkg),path.join(app,'packages',pkg),{recursive:true});
fs.cpSync(path.join(source,'packages/inventory-write'),path.join(app,'packages/inventory-write'),{recursive:true});
fs.symlinkSync(path.join(repo,'vendor'),path.join(app,'vendor'),'junction');fs.copyFileSync('composer.json',path.join(app,'composer.json'));
for(const d of ['bootstrap/cache','storage/logs','storage/framework/cache/data','storage/framework/sessions','storage/framework/views'])fs.mkdirSync(path.join(app,d),{recursive:true});
const hash=f=>crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex');
const nativeConnection={driver:'pgsql',host:'127.0.0.1',port:55439,database:nativeDb,username:nativeRole,password:nativePassword,charset:'utf8',prefix:'',search_path:'public',sslmode:'prefer'};
const demo=process.argv[2]==='demo';const env={...process.env,APP_ENV:'budget-testing',APP_KEY:'base64:'+crypto.randomBytes(32).toString('base64'),APP_DEBUG:'false',APP_BASE_PATH:app,DB_CONNECTION:'pgsql',DB_HOST:'127.0.0.1',DB_PORT:'55439',DB_DATABASE:hostDb,DB_USERNAME:hostRole,DB_PASSWORD:hostPassword,DB_URL:'',SESSION_DRIVER:'file',SESSION_COOKIE:'sgf_receipts_'+tag,CACHE_STORE:'array',QUEUE_CONNECTION:'sync',BCRYPT_ROUNDS:'4',SGF_ISOLATED_REGRESSION_RUN:state.id,SGF_REQUISITIONS_QA_ENABLED:'false',SGF_RECEIPTS_QA_ENABLED:'true',SGF_ORDERS_QA_ENABLED:orders?'true':'false',SGF_SOURCING_QA_ENABLED:sourcing?'true':'false',SGF_SUPPLIERS_QA_ENABLED:suppliers?'true':'false',SGF_STOCK_PERIOD_QA_ENABLED:stockPeriod?'true':'false',SGF_STOCK_RECEIPT_TRACE_QA_ENABLED:stockTrace?'true':'false',SGF_COMPOSITION_STOCK_READ_QA_ENABLED:stockComposition?'true':'false',SGF_OBLIGATION_EVIDENCE_QA_ENABLED:obligationEvidence?'true':'false',SGF_INVOICE_PROGRESS_QA_ENABLED:invoiceProgress?'true':'false',SGF_REQUEST_HISTORY_QA_ENABLED:requestHistory?'true':'false',SGF_PURCHASING_CONTINUITY_QA_ENABLED:continuity?'true':'false',SGF_PURCHASING_FOCUS_QA_ENABLED:focus?'true':'false',SGF_RECEIPT_DOCUMENTS_QA_ENABLED:receiptDocuments?'true':'false',SGF_SUPPLIER_DOCUMENTS_QA_ENABLED:supplierDocuments?'true':'false',SGF_DOSSIERS_QA_ENABLED:dossiers?'true':'false',SGF_REQUESTS_QA_ENABLED:requests?'true':'false',PAYABLE_SOURCE_INSTANCE:obligations?'qa-stock-ledger-'+tag:'',SGF_OBLIGATIONS_QA_ENABLED:obligations?'true':'false',SGF_INVOICES_QA_ENABLED:invoices?'true':'false',SGF_GEOGRAPHY_QA_ENABLED:geography?'true':'false',SGF_GEOGRAPHY_SOURCE_SHA256:'70996d9a9133785a848de90bedb4bf685e24d8f823cd153c0adc43eac642a292',SGF_RECEIPTS_QA_PROFILE:path.join(root,'binding.json'),RECEIPT_COMPOSITION_STATE:path.join(root,'state.json'),...(demo?{RECEIPT_PROOF_PREPARE_ONLY:'true'}:{})};
fs.writeFileSync(path.join(root,'state.json'),JSON.stringify({tag,root,app,bundle,env,nativeConnection,orders,sourcing,suppliers,requests,stockPeriod,stockTrace,stockComposition,obligationEvidence,invoiceProgress,requestHistory,continuity,focus,receiptDocuments,supplierDocuments,receiptWorkspace,dossiers,supplierSearch,integrated,geography,obligations,invoices,manifest_sha256:hash(path.join(bundle,'manifest.json'))},null,2));
console.log(JSON.stringify({tag,root,native_setup:true,namespace_bundle:true}));
if(integrated){for(const [file,log]of [['receipt-composition-proof.php','host-schema'],['order-host-setup.php','order-host'],['sourcing-host-setup.php','sourcing-host'],['supplier-host-setup.php','supplier-host'],['request-host-setup.php','request-host'],['geography-host-setup.php','geography-host'],['invoice-host-setup.php','invoice-host'],['obligation-host-setup.php','obligation-host'],['purchasing-integrated-setup.php','integrated-host']])run([path.join(repo,'scripts',file)],app,{...env,RECEIPT_PROOF_PREPARE_ONLY:'true'},log);if(!demo)run([path.join(repo,'scripts/purchasing-integrated-proof.php')],app,env,'integrated-proof');}else if(orders){run([path.join(repo,'scripts/receipt-composition-proof.php')],app,{...env,RECEIPT_PROOF_PREPARE_ONLY:'true'},'host-schema');run([path.join(repo,'scripts/order-host-setup.php')],app,env,'order-host');if(sourcing){run([path.join(repo,'scripts/sourcing-host-setup.php')],app,env,'sourcing-host');if(suppliers){run([path.join(repo,'scripts/supplier-host-setup.php')],app,env,'supplier-host');if(requests){run([path.join(repo,'scripts/request-host-setup.php')],app,env,'request-host');if(geography){run([path.join(repo,'scripts/geography-host-setup.php')],app,env,'geography-host');if(!demo)run([path.join(repo,'scripts/geography-composition-proof.php')],app,env,'geography-proof');}else if(!demo){run([path.join(repo,'scripts/request-composition-proof.php')],app,env,'request-proof');if(!fs.existsSync(path.join(root,'request-result.json')))throw Error('Request proof did not complete; do not continue dependent workflow');run([path.join(repo,'scripts/sourcing-composition-proof.php')],app,env,'request-sourcing-proof');}}else if(!demo)run([path.join(repo,'scripts/supplier-composition-proof.php')],app,env,'supplier-proof');}else if(!demo)run([path.join(repo,'scripts/sourcing-composition-proof.php')],app,env,'sourcing-proof');}else if(invoices){run([path.join(repo,'scripts/invoice-host-setup.php')],app,env,'invoice-host');if(obligations)run([path.join(repo,'scripts/obligation-host-setup.php')],app,env,'obligation-host');if(!demo&&obligations)run([path.join(repo,'scripts/obligation-composition-proof.php')],app,env,'obligation-proof');else if(!demo)run([path.join(repo,'scripts/invoice-composition-proof.php')],app,env,'invoice-proof');}else if(!demo)run([path.join(repo,'scripts/order-composition-proof.php')],app,env,'order-proof');}else run([path.join(repo,'scripts/receipt-composition-proof.php')],app,env,'composition-proof');
if(stockComposition){run([path.join(repo,'scripts/composition-stock-setup.php')],app,env,'composition-stock-setup');if(!fs.existsSync(path.join(root,'composition-stock-baseline.json')))throw Error('Stock setup incomplete');}
console.log(JSON.stringify({tag,passed:JSON.parse(fs.readFileSync(path.join(root,integrated?(demo?'integrated-baseline.json':'integrated-result.json'):obligations?(demo?'obligation-baseline.json':'obligation-result.json'):invoices?(demo?'invoice-baseline.json':'invoice-result.json'):geography?(demo?'geography-baseline.json':'geography-result.json'):requests?(demo?'request-baseline.json':'request-result.json'):suppliers?(demo?'supplier-baseline.json':'supplier-result.json'):sourcing?(demo?'sourcing-baseline.json':'sourcing-result.json'):orders?(demo?'order-baseline.json':'order-result.json'):(demo?'demo-baseline.json':'result.json')))).passed,demo}));