Regista aceitacao tecnica da consolidacao sintetica de fornecedores
This commit is contained in:
@@ -138,4 +138,6 @@ Próximo passo: a equipa testa as duas interfaces e relata função, origem/capt
|
||||
|
||||
## Retoma da interface — 30/10/2026
|
||||
|
||||
Retoma automática posterior: [resultados consolidados SGF/Compras](SUPPLIER_SETTLEMENT_CONSOLIDATION_20261030.md). Verificações adicionais aprovadas sem alterar motor, permissões existentes ou dados persistentes; revisão visual separada e pendente.
|
||||
|
||||
A página de obrigações passou a mostrar afectações novas e saldo por liquidar da posição canónica, preservando o principal. Percurso HTTP/HTML repetido em Compras e SGF: 11 600 MZN → pagamento confirmado sem abatimento → afectação confirmada de 4 000 → saldo 7 600; vencimento/dias nulos. Provas anteriores preservadas. Resultados, correcções de navegação e bloqueio visual no [relatório de pagamentos](SUPPLIER_SETTLEMENT_DELIVERY.md), secção Consolidação do percurso. Sem habilitação pública, mudança de permissões ou encerramento presumido.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Consolidação automática — SGF e Compras, 30/10/2026
|
||||
|
||||
Conferidos primeiro SUPPLIER_SETTLEMENT_DELIVERY.md, SUPPLIER_PAYABLE_DELIVERY.md e as respectivas provas. A sequência HTTP/HTML já estava aprovada nas duas composições. Concorrência, isolamento, revogação e recuperação têm provas existentes, reutilizadas sem repetir a bateria. O SHA-256 de SupplierSettlements.php continua igual ao da prova original: `156bd40f3080de66a73c0befd975990e9d7010c2a232a86d751d4db3af4fae93`.
|
||||
|
||||
## Cobertura completada
|
||||
|
||||
Acrescentadas asserções em `scripts/settlements-interface-check.mjs`: dívida inalterada enquanto o pagamento é proposto; repetição da confirmação com nova chave recupera a mesma decisão; actor de confirmação diferente do preparador tanto no pagamento como na afectação; exactamente quatro eventos, um por etapa, sem eventos adicionais na repetição; IDs do histórico preservados após sair e voltar a entrar.
|
||||
|
||||
Estas verificações precisaram de uma nova sequência de preparação em bases descartáveis. Nenhum direito foi modificado nas instalações existentes: o instalador de fixture apenas preparou os acessos sintéticos das bases novas de prova. Nenhum comando financeiro foi executado nas demonstrações persistentes.
|
||||
|
||||
| Resultado HTTP automático | Compras autónomo | SGF |
|
||||
| --- | --- | --- |
|
||||
| Principal reconhecido | 11 600 MZN | 11 600 MZN |
|
||||
| Pagamento de 4 000 proposto e depois confirmado | Dívida mantém 11 600 MZN | Dívida mantém 11 600 MZN |
|
||||
| Afectação proposta, ainda não confirmada | Dívida mantém 11 600 MZN | Dívida mantém 11 600 MZN |
|
||||
| Afectação de 4 000 confirmada por outra identidade | Saldo 7 600 MZN | Saldo 7 600 MZN |
|
||||
| Vencimento / dias de atraso | null / null; indeterminado | null / null; indeterminado |
|
||||
| Repetição e reentrada | Um pagamento, uma afectação, quatro eventos | Um pagamento, uma afectação, quatro eventos |
|
||||
|
||||
Evidência: [nova prova](proofs/supplier-settlements-consolidation-20261030.json). Preservadas as provas supplier-settlements.json e supplier-settlements-interface-20261030.json.
|
||||
|
||||
Executados `settlements-interface-run.py`, sintaxe Node do verificador, regressão de navegação/página inicial (`home-navigation-check.mjs`) e `git diff --check`, todos aprovados. O runner terminou e removeu os seus processos, bases e roles. Nenhum novo defeito funcional foi encontrado; só o verificador e documentação foram alterados. Builds e regressões financeiras anteriores são reutilizados: não houve alteração de código de aplicação, motor, adaptadores ou dependências nesta retoma.
|
||||
|
||||
## Limitações e encerramento
|
||||
|
||||
**Revisão visual pendente**, sem tentativa de navegador nesta retoma. O diagnóstico anterior mais recente substitui o antigo bloqueio de pipe: Firefox interrompido com `browser URL policy enforcement is not yet supported for the current Windows browser`. Não se contornou o bloqueio. HTTP/HTML e VM não comprovam disposição, legibilidade, foco ou utilização por cliques.
|
||||
|
||||
MFA continua com dois testes ignorados já documentados: `users with two factor enabled are redirected to two factor challenge` e `security page is displayed`. São cobertura de autenticação pendente, não prova do efeito monetário.
|
||||
|
||||
## Aceitação técnica e checkpoint local — 30/10/2026
|
||||
|
||||
O responsável aceitou expressamente esta consolidação e autorizou o checkpoint exclusivamente local, preservando alterações alheias e excluindo credenciais e dados privados. Fica aceite o resultado técnico nas duas composições; a revisão visual continua pendente e não é declarada realizada ou aceite. Os dois testes MFA permanecem pendentes nos termos acima.
|
||||
|
||||
O checkpoint inclui apenas o verificador, a prova sintética e a documentação desta consolidação. Não autoriza utilização real, publicação ou habilitação do percurso público. Não houve alteração de permissões existentes, operações bancárias, correcções de afectações ou novos módulos. A página inicial mantém-se limpa. Mantêm-se os restantes limites do relatório de entrega, incluindo históricos importados e ausência de reconciliação/contabilidade/stock/orçamento adicional.
|
||||
@@ -4,6 +4,8 @@ Implementado o incremento seguinte às obrigações, nas duas composições, com
|
||||
|
||||
## Responsabilidade e código
|
||||
|
||||
Actualização de 30/10/2026: [consolidação automática sem navegador](SUPPLIER_SETTLEMENT_CONSOLIDATION_20261030.md). Complementa as provas abaixo, sem as substituir; cobertura adicional de repetição da confirmação, identidade distinta e eventos únicos aprovada nas duas composições. Revisão visual continua pendente.
|
||||
|
||||
O código comum reside em `packages/payables/src/SupplierSettlements.php`, `SettlementSchema.php`, `SettlementHttp.php` e `ui/settlements.php`. Carregamento e apresentação em `bootstrap.php` e `src/Workspace.php`. `src/Payables.php` conserva a responsabilidade única pelo saldo: principal menos histórico confirmado existente e afectações novas confirmadas. Não se escrevem pagamentos externos legados para representar novamente o mesmo facto.
|
||||
|
||||
Os adaptadores são `app/Modules/Purchasing/SupplierPaymentsController.php` no SGF e `app/Http/Controllers/SupplierPaymentsController.php` em Compras, apoiados nos respectivos `SupplierPayables.php`. Contexto, pessoa, organização e direitos são revalidados no servidor pelos adaptadores existentes; o motor recebe contexto explícito. Rotas em `routes/web.php` de cada aplicação. A página anterior de obrigações apresenta a ligação quando disponível. No SGF, `resources/js/WorkspaceNavigation.jsx` e `app.jsx` incluem a entrada; nenhuma concessão real foi adicionada.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"checked_at": "2026-10-30T21:28:42.382Z",
|
||||
"core_unchanged": true,
|
||||
"core_sha256": "156bd40f3080de66a73c0befd975990e9d7010c2a232a86d751d4db3af4fae93",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "compras",
|
||||
"passed": true,
|
||||
"kind": "HTTP pages, form availability, submitted commands and JavaScript syntax; not browser execution",
|
||||
"stages": [
|
||||
{
|
||||
"stage": "recognised",
|
||||
"debt_minor": 1160000
|
||||
},
|
||||
{
|
||||
"stage": "payment_confirmed_before_allocation",
|
||||
"debt_minor": 1160000,
|
||||
"unallocated_minor": 400000
|
||||
},
|
||||
{
|
||||
"stage": "allocation_confirmed",
|
||||
"debt_minor": 760000,
|
||||
"unallocated_minor": 0
|
||||
}
|
||||
],
|
||||
"principal_minor": 1160000,
|
||||
"due_on": null,
|
||||
"days_overdue": null,
|
||||
"payments": 1,
|
||||
"allocations": 1,
|
||||
"repeat_recovered": true,
|
||||
"payment_confirmation_repeat_recovered": true,
|
||||
"event_counts": {
|
||||
"supplier_payment.proposed": 1,
|
||||
"supplier_payment.confirmed": 1,
|
||||
"supplier_allocation.proposed": 1,
|
||||
"supplier_allocation.confirmed": 1
|
||||
},
|
||||
"distinct_validation_actors": true,
|
||||
"history_after_reentry": true,
|
||||
"canonical_balance_on_both_pages": true,
|
||||
"role_destination_retained": true,
|
||||
"external_redirect_refused": true,
|
||||
"read_only_without_forms": true,
|
||||
"visual_review": false
|
||||
},
|
||||
{
|
||||
"host": "sgf",
|
||||
"passed": true,
|
||||
"kind": "HTTP pages, form availability, submitted commands and JavaScript syntax; not browser execution",
|
||||
"stages": [
|
||||
{
|
||||
"stage": "recognised",
|
||||
"debt_minor": 1160000
|
||||
},
|
||||
{
|
||||
"stage": "payment_confirmed_before_allocation",
|
||||
"debt_minor": 1160000,
|
||||
"unallocated_minor": 400000
|
||||
},
|
||||
{
|
||||
"stage": "allocation_confirmed",
|
||||
"debt_minor": 760000,
|
||||
"unallocated_minor": 0
|
||||
}
|
||||
],
|
||||
"principal_minor": 1160000,
|
||||
"due_on": null,
|
||||
"days_overdue": null,
|
||||
"payments": 1,
|
||||
"allocations": 1,
|
||||
"repeat_recovered": true,
|
||||
"payment_confirmation_repeat_recovered": true,
|
||||
"event_counts": {
|
||||
"supplier_payment.proposed": 1,
|
||||
"supplier_payment.confirmed": 1,
|
||||
"supplier_allocation.proposed": 1,
|
||||
"supplier_allocation.confirmed": 1
|
||||
},
|
||||
"distinct_validation_actors": true,
|
||||
"history_after_reentry": true,
|
||||
"canonical_balance_on_both_pages": true,
|
||||
"role_destination_retained": true,
|
||||
"external_redirect_refused": true,
|
||||
"read_only_without_forms": true,
|
||||
"visual_review": false
|
||||
}
|
||||
],
|
||||
"visual_blocker": "Previous Firefox attempt stopped: browser URL policy enforcement is not yet supported for the current Windows browser. Browser not retried in this consolidation.",
|
||||
"public_enabled": false,
|
||||
"bank_execution": false,
|
||||
"accepted_proof_preserved": true
|
||||
}
|
||||
@@ -41,8 +41,11 @@ for(const mode of ['compras','sgf']) {
|
||||
await checkFormFeedback(html);
|
||||
const paymentBody={obligation_id:obligation.id,source_revision:obligation.source_revision,amount:'4000.00',currency:'MZN',paid_on:new Date().toISOString().slice(0,10),fact_reference:'SIM-INTERFACE-PAY-001',evidence_reference:'SIM-INTERFACE-EVID-001',reason:'Pagamento sintético de 4 000 MZN sem execução bancária'};
|
||||
const payment=await p.submit('/api/supplier-payments','payment-prepare',paymentBody);assert.equal((await p.submit('/api/supplier-payments','payment-prepare',paymentBody)).payment_id,payment.payment_id);
|
||||
data=await q.position();assert.equal(data.obligations[0].balance_minor,1160000);assert.equal(data.payments[0].state,'proposed');
|
||||
await v.enter('validacao','payments');await v.page('/supplier-payments','payment-decide');const decision={payment_id:payment.payment_id,decision:'confirmed',evidence_reference:'SIM-INTERFACE-CONF-001',reason:'Conferência independente de evidência artificial'};
|
||||
await v.submit('/api/supplier-payments','payment-decide',decision);data=await q.position();assert.equal(data.obligations[0].balance_minor,1160000);assert.equal(data.payments[0].unallocated_minor,400000);stages.push({stage:'payment_confirmed_before_allocation',debt_minor:1160000,unallocated_minor:400000});
|
||||
const paymentDecision=await v.submit('/api/supplier-payments','payment-decide',decision);
|
||||
assert.equal((await v.submit('/api/supplier-payments','payment-decide',decision)).decision_id,paymentDecision.decision_id);
|
||||
data=await q.position();assert.equal(data.obligations[0].balance_minor,1160000);assert.equal(data.payments[0].unallocated_minor,400000);stages.push({stage:'payment_confirmed_before_allocation',debt_minor:1160000,unallocated_minor:400000});
|
||||
html=await q.page(obligations);assert(/Saldo por liquidar: 11 600\.00 MZN/.test(html));
|
||||
await p.page('/supplier-payments','allocation-prepare');const plan={payment_id:payment.payment_id,reference:'SIM-INTERFACE-ALLOC-001',allocations:[{obligation_id:obligation.id,source_revision:obligation.source_revision,amount:'4000.00'}],reason:'Afectação explícita sem segundo efeito na obrigação'};
|
||||
const allocation=await p.submit('/api/supplier-payments','allocation-prepare',plan);assert.equal((await q.position()).obligations[0].balance_minor,1160000);
|
||||
@@ -52,11 +55,19 @@ for(const mode of ['compras','sgf']) {
|
||||
html=await q.page('/supplier-payments');assert(html.includes('7 600.00 MZN'));assert(html.includes('Atraso indeterminado'));assert(html.includes('Dias de atraso: sem valor'));assert(!html.includes('data-action='));
|
||||
html=await q.page(obligations);assert(/Saldo por liquidar: 7 600\.00 MZN/.test(html));assert(html.includes('11 600.00 MZN'));assert(html.includes('4 000.00 MZN'));assert(html.includes('Atraso indeterminado'));
|
||||
await p.page('/supplier-payments');assert(!(await p.page('/supplier-payments')).includes('data-action="allocation-prepare"'),'Exhausted payment should not be offered for new allocation');
|
||||
await q.leave();await q.enter('consulta','payments');data=await q.position();assert.equal(data.obligations[0].balance_minor,760000);assert.equal(data.allocations.length,1);assert(data.events.length>=4);
|
||||
const eventCounts=Object.fromEntries([...new Set(data.events.map(e=>e.kind))].map(kind=>[kind,data.events.filter(e=>e.kind===kind).length]));
|
||||
assert.equal(data.events.length,4);assert(Object.values(eventCounts).every(count=>count===1));
|
||||
const paymentEvent=data.events.find(e=>e.kind==='supplier_payment.confirmed'),allocationEvent=data.events.find(e=>e.kind==='supplier_allocation.confirmed');
|
||||
assert(paymentEvent);assert(allocationEvent);
|
||||
assert.notEqual(String(data.payments[0].prepared_by),String(paymentEvent.actor_id));
|
||||
const allocationProposal=data.allocation_proposals.find(item=>Number(item.id)===allocation.proposal_id);
|
||||
assert.notEqual(String(allocationProposal.prepared_by),String(allocationEvent.actor_id));
|
||||
const eventIds=data.events.map(e=>e.id);
|
||||
await q.leave();await q.enter('consulta','payments');data=await q.position();assert.equal(data.obligations[0].balance_minor,760000);assert.equal(data.allocations.length,1);assert.deepEqual(data.events.map(e=>e.id),eventIds);
|
||||
await q.page('/demo?next=payments');const bad=await q.request('/demo/entrar','POST',{role:'consulta',next:'https://example.test'},true);assert.equal(bad.status,422);
|
||||
await p.leave();await v.leave();await q.leave();
|
||||
hosts.push({host:mode,passed:true,kind:'HTTP pages, form availability, submitted commands and JavaScript syntax; not browser execution',stages,principal_minor:1160000,due_on:null,days_overdue:null,payments:1,allocations:1,repeat_recovered:true,history_after_reentry:true,canonical_balance_on_both_pages:true,role_destination_retained:true,external_redirect_refused:true,read_only_without_forms:true,visual_review:false});
|
||||
hosts.push({host:mode,passed:true,kind:'HTTP pages, form availability, submitted commands and JavaScript syntax; not browser execution',stages,principal_minor:1160000,due_on:null,days_overdue:null,payments:1,allocations:1,repeat_recovered:true,payment_confirmation_repeat_recovered:true,event_counts:eventCounts,distinct_validation_actors:true,history_after_reentry:true,canonical_balance_on_both_pages:true,role_destination_retained:true,external_redirect_refused:true,read_only_without_forms:true,visual_review:false});
|
||||
console.log(mode+': full synthetic sequence passed; single payment/allocation, debt 11600 before allocation and 7600 after.');
|
||||
}
|
||||
const core=await fs.readFile('packages/payables/src/SupplierSettlements.php');const coreSha=createHash('sha256').update(core).digest('hex');const accepted=JSON.parse(await fs.readFile('docs/proofs/supplier-settlements.json','utf8'));assert(accepted.hosts.every(h=>h.core_sha256===coreSha),'Financial core changed since accepted proof');
|
||||
await fs.writeFile('docs/proofs/supplier-settlements-interface-20261030.json',JSON.stringify({checked_at:new Date().toISOString(),core_unchanged:true,core_sha256:coreSha,hosts,visual_blocker:'Computer Use native pipe is unavailable: failed to connect native pipe (OS error 2)',public_enabled:false,bank_execution:false,accepted_proof_preserved:true},null,2)+'\n');
|
||||
await fs.writeFile('docs/proofs/supplier-settlements-consolidation-20261030.json',JSON.stringify({checked_at:new Date().toISOString(),core_unchanged:true,core_sha256:coreSha,hosts,visual_blocker:'Previous Firefox attempt stopped: browser URL policy enforcement is not yet supported for the current Windows browser. Browser not retried in this consolidation.',public_enabled:false,bank_execution:false,accepted_proof_preserved:true},null,2)+'\n');
|
||||
|
||||
Reference in New Issue
Block a user