From e38aa74920412e545213b35b7585c847a0b8a969 Mon Sep 17 00:00:00 2001 From: nala Date: Sun, 25 Oct 2026 11:04:59 +0200 Subject: [PATCH] Authorize grouped installer after authenticated backup and isolated restore --- .../l1-tempo-offers-fx-delivery-20261025.json | 69 ++++++++++++++++++- ...offers-fx-readonly-rollback-20261025.patch | 16 +++-- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/docs/investmoz/simulations/l1-tempo-offers-fx-delivery-20261025.json b/docs/investmoz/simulations/l1-tempo-offers-fx-delivery-20261025.json index a77ca041..645c57c8 100644 --- a/docs/investmoz/simulations/l1-tempo-offers-fx-delivery-20261025.json +++ b/docs/investmoz/simulations/l1-tempo-offers-fx-delivery-20261025.json @@ -1,5 +1,5 @@ { - "status": "prepared_awaiting_fresh_preflight_backup_restore", + "status": "ready_after_fresh_authenticated_preflight_and_verified_backup_restore", "candidate": "7b6a95a7181be5af622b0b665a31010ce93d6d5c", "accepted_candidates": [ "7b6a95a7" @@ -172,5 +172,70 @@ "P084_P085_closure": false, "P058_closure": false, "L1": "open", - "containment": "l1-tempo-offers-fx-readonly-rollback-20261025.patch verified without applying;retains readers/history/downloads and unrelated branches;previous release retained" + "containment": "l1-tempo-offers-fx-readonly-rollback-20261025.patch verified without applying;retains readers/history/downloads and unrelated branches;previous release retained", + "authenticated_preflight": { + "installed": { + "status": "installed", + "commit": "a665ee9c974adb48706027e66fdd71b773d7358c", + "release": "/var/www/investmoz-homologacao/releases/a665ee9c974adb48706027e66fdd71b773d7358c-67adcc0e", + "previous_release": "/var/www/investmoz-homologacao/releases/a48e9749799b7ed0ad370e23c2fda2bab06150d0-4bcb51fd", + "database_migrations": 0, + "content_imports": 0 + }, + "current_link": "/var/www/investmoz-homologacao/releases/a665ee9c974adb48706027e66fdd71b773d7358c-67adcc0e", + "release_revision": { + "commit": "a665ee9c974adb48706027e66fdd71b773d7358c", + "branch": "main", + "built_at": "2026-10-25T08:24:49.843479+00:00", + "manifest_sha256": "4aa78f9db6db6dcf31222b9bff45f5dfbaa0dc071225fcc3de4f0f02f0d03cd8" + }, + "service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n", + "configuration_keys": [ + "repository", + "branch", + "target_url", + "legacy_root", + "state_root", + "release_root", + "current_link", + "shared_assets", + "php", + "schema_contract", + "ci_environment", + "postgis_image", + "test_database", + "qa_port", + "retention", + "webhook_secret_file" + ], + "safe_paths": { + "repository": "nala/Investidor-V2", + "release_root": "/var/www/investmoz-homologacao/releases", + "postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6" + }, + "pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604" + }, + "backup_restore": { + "backup": { + "stage": "/var/backups/investmoz-l1-tempo-offers-fx-delivery-20261025/backup", + "target": { + "database": "teste_investidor", + "port": 5432 + }, + "tables": 174, + "files_verified": 369, + "dump_sha256": "15f6d2f8bee7c1b21ba02406e311d1a6e203dfe3081aa84997c3057ea19c2a73", + "files_sha256": "bb0db583f66e8f890808573a7f63d36f67242306f90cab2a3dc07e412ee6edef", + "restore_verified": false + }, + "restore": { + "restore_verified": true, + "tables_verified": 174, + "container_network": "none", + "database": "l1_tempo_offers_fx_restore_20261025", + "port": 55441, + "source_dump_sha256": "15f6d2f8bee7c1b21ba02406e311d1a6e203dfe3081aa84997c3057ea19c2a73", + "active_database_writes": 0 + } + } } diff --git a/docs/investmoz/simulations/l1-tempo-offers-fx-readonly-rollback-20261025.patch b/docs/investmoz/simulations/l1-tempo-offers-fx-readonly-rollback-20261025.patch index b12bdb9f..5468aa92 100644 --- a/docs/investmoz/simulations/l1-tempo-offers-fx-readonly-rollback-20261025.patch +++ b/docs/investmoz/simulations/l1-tempo-offers-fx-readonly-rollback-20261025.patch @@ -1,12 +1,14 @@ --- a/resources/js/lib/iva-currency-events.ts +++ b/resources/js/lib/iva-currency-events.ts -@@ -99,5 +99,5 @@ - } - function key(draft:Record,book:CurrencyEventBook):string{return JSON.stringify({version:currencyEventVersion,scope:acquisitionScope(draft),location:draft.selection_labels??{},rows:book.rows});} - export function currencyEventCurrent(draft:Record,book:CurrencyEventBook):boolean{return!!book.result&&book.result.sourceKey===key(draft,book);} --export function recordCurrencyEvents(draft:Record,book:CurrencyEventBook):CurrencyEventBook{if(!book.rows.length||new Set(book.rows.map(r=>r.id)).size!==book.rows.length)throw new Error('Indique operações com identidades distintas;originais conservados.');const result:CurrencyEventCalculation={version:currencyEventVersion,revision:(book.result?.revision??0)+1,calculatedAt:new Date().toISOString(),opportunity:acquisitionScope(draft),location:JSON.stringify(draft.selection_labels??{}),sourceKey:key(draft,book),source:currencyEventSource,inputs:structuredClone(book.rows),rows:book.rows.map(evaluateCurrencyEvent)};const next={...book,result,history:[...(book.history??[]),...(book.result?[book.result]:[])]};saveCurrencyEventBook(draft,next);return next;} -+export function recordCurrencyEvents(draft:Record,book:CurrencyEventBook):CurrencyEventBook{if(book.rows.some(row=>row.treatment==='foreign_scenario'&&row.fxSelection))throw new Error('Novas versões operacionaisP104 temporariamente suspensas;históricos e outros eventos conservados.');if(!book.rows.length||new Set(book.rows.map(r=>r.id)).size!==book.rows.length)throw new Error('Indique operações com identidades distintas;originais conservados.');const result:CurrencyEventCalculation={version:currencyEventVersion,revision:(book.result?.revision??0)+1,calculatedAt:new Date().toISOString(),opportunity:acquisitionScope(draft),location:JSON.stringify(draft.selection_labels??{}),sourceKey:key(draft,book),source:currencyEventSource,inputs:structuredClone(book.rows),rows:book.rows.map(evaluateCurrencyEvent)};const next={...book,result,history:[...(book.history??[]),...(book.result?[book.result]:[])]};saveCurrencyEventBook(draft,next);return next;} - export function currencyEventReportRows(draft:Record):Array<[string,string,string,string]>{try{const book=currencyEventBook(draft),r=book.result;if(!r)return[];return r.inputs.map((row,i):[string,string,string,string]=>{if(row.treatment==='foreign_scenario'&&row.fxSelection)return['IVA mensal',`P104 — ${row.period} — ${row.id}`,`${row.description};${r.rows[i].reason};Original:${row.amount} ${row.sourceCurrency};Convertido:${r.rows[i].scenarioAmount??'Indeterminado'} MZN`,`${r.opportunity};${currencyEventCurrent(draft,book)?'Resultado actual':'Entradas alteradas;resultado histórico conservado'};versão${r.revision};${r.calculatedAt};documento:${row.documentRef},${row.documentDate};âmbito:${row.scope};boletim:${row.fxSelection.bulletinRef};fonte:${row.fxSelection.source};natureza:${row.fxSelection.nature};perspectiva:${row.fxSelection.bulletinPerspective};relação:${row.fxSelection.relation};taxa:${row.fxRate};data:${row.fxDate};sentido:${row.fxDirection};regra/excepção:${row.fxRuleRef};sem base/IVA/dedução activados.`];return['IVA mensal',`${currencyEventTreatments.find(t=>t.id===row.treatment)?.branch??'Evento'} — ${row.period} — ${row.id}`,`${row.description};${r.rows[i].reason};facto gerador:${r.rows[i].eventDate??'Indeterminado/não apurado'};parcelas:${r.rows[i].dueEvents.map(p=>p.date+': '+(p.amount??'Montante indeterminado')+' '+row.currency+' ('+p.reason+')').join('; ')||'Nenhuma apurada'};restante pendente:${r.rows[i].status==='indeterminate'?'Indeterminado':r.rows[i].remainingPending?'Sim':'Não'};${row.treatment==='foreign_scenario'&&r.rows[i].status==='determined'?'conversão operacional':'cenário condicionado'}:${r.rows[i].scenarioAmount??'Indeterminado'};base/IVA:Indeterminados`,`${r.opportunity};${r.location};${currencyEventCurrent(draft,book)?'Resultado actual':'Entradas alteradas;resultado histórico conservado'};versão${r.revision};${r.calculatedAt};${r.source};${row.origin};documento ${row.documentRef},${row.documentDate};ambito ${row.scope};${row.treatment==='foreign_scenario'?`origem ${row.amount} ${row.sourceCurrency};taxa ${row.fxRate},${row.fxDirection},${row.fxDate};fonte ${row.fxSource};pressuposto ${row.fxRuleRef}`:`evento ${row.eventDate},${row.eventRef};outra data ${row.otherDate};conferencia ${row.reviewDate};factura ${row.invoiceRequired},${row.invoiceState},${row.invoiceDate},${row.invoiceRef};prazo ${row.legalDeadline},${row.deadlineRef};recebimento ${row.paymentState},${row.paymentDate},${row.paymentAmount},${row.paymentRef};total do ambito ${row.amount} ${row.currency}`};fundamento ${row.evidence};sem nova dedução/campo11/IVA ou activação cambial nos livros anteriores.`];});}catch{return[['IVA mensal','Moeda/eventos','Dados não recuperáveis','Originais preservados;sem substituição porzero.']];}} +@@ -44,7 +44,7 @@ + if(!/^2026-(0[1-9]|1[0-2])$/.test(row.period)||!['projected','effective'].includes(row.origin)||date(row.documentDate)===null||![row.description,row.operationRef,row.documentRef,row.scope,row.evidence].every(v=>!!v.trim()))return stop('Identifique mês de contexto2026,operação,documento/data,âmbito e factos ou pressupostos expressos.'); + if(row.factsConfirmed==='no')return stop('Os factos declarados afastam este percurso;sem isenção ou IVA zero por defeito.','not_applicable'); + if(row.factsConfirmed!=='yes')return stop('Factos do percurso por esclarecer;não usar datas ou câmbio por defeito.'); +- if(row.treatment==='foreign_scenario'){ ++ if(row.treatment==='foreign_scenario'){if(row.fxSelection)return stop('Novas conversões operacionaisP104 temporariamente suspensas;históricos e outros eventos conservados.'); + const amount=decimal(row.amount),fx=decimal(row.fxRate,8); + if(row.currency!=='MZN'||!['USD','EUR','ZAR','GBP','CNY','BRL','JPY','CHF','AUD','CAD'].includes(row.sourceCurrency)||amount===null||fx===null||fx===0n||date(row.fxDate)===null||![row.fxSource,row.fxRuleRef].every(v=>!!v.trim())||!['mzn_per_unit','units_per_mzn'].includes(row.fxDirection))return stop('Indique moeda original,valor,taxa positiva,direcção,data,fonte e regra/pressuposto expresso.Sem substituir moeda original porMZN ou reutilizar taxa de apresentação como regra fiscal.'); + result.scenarioAmount=money(row.fxDirection==='mzn_per_unit'?convertScaledAmount(amount,fx,100000000n):(amount*100000000n+fx/2n)/fx); --- a/resources/js/lib/iva-offer-workflow.ts +++ b/resources/js/lib/iva-offer-workflow.ts @@ -8,7 +8,7 @@