Files
SGF/docs/SUPPLIER_ALLOCATION_REVERSAL_DELIVERY.md
T
2026-11-02 08:06:45 +02:00

86 lines
12 KiB
Markdown

# Reversão integral de afectações — entrega técnica, 30/10/2026
Incremento `COMMON-ALLOCATION-FULL-REVERSAL-SIM-v1`, sobre os checkpoints aceites SGF `e4f520092e8aa3261880b8b91fca0fdf789086ce` e Compras `13a6cb9922af5004c636697c49f229d4a97f231c`. Esses checkpoints e provas anteriores foram preservados. Esta entrega não presume aceitação e não cria novo checkpoint.
## Responsabilidade e comportamento
Único motor: `packages/payables/src/SupplierSettlements.php`. O cálculo canónico de Payables continua a chamar `allocated()`, agora com afectações confirmadas menos compensações integrais confirmadas. O disponível do pagamento segue a mesma regra. Não se escreve um segundo saldo nem se alteram principal, impostos, documento, pagamento, afectação ou decisões originais.
- `reversal-prepare`: recebe ID estável da afectação, versão da origem e motivo obrigatório. Cria uma proposta única por afectação, sem efeito monetário.
- `reversal-confirm`: recebe ID da proposta e motivo obrigatório da decisão. Exige outra identidade **e outra pessoa**, revalida contexto, direitos e versão, e acrescenta o movimento compensatório integral ligado ao original. Não cancela o pagamento.
- A nova afectação usa os comandos anteriores e uma nova referência. Revalida fornecedor, moeda, versão, saldo da obrigação e disponível do pagamento. A ligação original revertida não impede a nova ligação.
- Referências antigas e suas repetições recuperam o resultado original, incluindo depois da reversão; não reaplicam o efeito revertido. Conteúdo incompatível gera conflito. Uma proposta com o mesmo plano pode existir num novo ciclo após reversão, sem confundir repetição com uma nova correcção.
- O ciclo é por pagamento e corresponde à última compensação confirmada. Uma proposta de afectação ainda não decidida de um ciclo anterior não pode ser confirmada depois de uma reversão; exige nova preparação/referência. Decisões originais já confirmadas continuam recuperáveis sem novo efeito.
- Motivo e autoria da preparação/confirmação ficam em registos imutáveis; eventos e outbox são gravados na mesma transacção dos comandos e movimentos. Confirmação concorrente recupera o mesmo movimento.
O motor continua a receber actor, pessoa, organização e callbacks explícitos. As permissões/contextos dos hosts continuam nos adaptadores existentes: SGF `app/Modules/Purchasing/SupplierPayables.php`; Compras `app/Services/SupplierPayables.php`. Não foram equiparados tenant, empresa ou unidade. Não há dependência de facturação de vendas ou de um SGF remoto.
## Interfaces e direitos
`SettlementHttp.php` expõe a consulta das propostas/compensações e verifica o utilizador funcional do host. `ui/settlements.php`, a mesma página nas duas composições, acrescenta a secção «Reversão integral e nova afectação», com motivo, confirmação independente, montante integral, ligação ao original, histórico e explicação de que o pagamento continua confirmado. O formulário não permite indicar um montante de reversão. A consulta não recebe formulários de escrita. O servidor revalida tudo, mesmo que o cliente seja alterado.
As duas `routes/web.php` permitem apenas os dois novos comandos nos endpoints autenticados existentes. Novas capacidades explícitas: `reversal_prepare` e `reversal_confirm`; não derivam automaticamente dos direitos de afectação. Só foram outorgadas às identidades sintéticas de **bases descartáveis** pelo instalador de prova. Nenhum direito público, real ou das demonstrações persistentes foi modificado. Página inicial preservada sem cartões/resumos.
## Actualização de esquema e preservação
`src/ReversalSchema.php` é uma actualização QA explícita e transaccional, não uma migração operacional registada:
1. Acrescenta `ps_reversal_proposals` e `ps_reversals`, com unicidade por afectação, chaves estrangeiras e triggers append-only.
2. Um trigger de integridade exige compensação do montante inteiro, pagamento/obrigação/contexto/versão correspondentes e confirmação por actor/pessoa diferentes do preparador.
3. Acrescenta `ps_proposals.allocation_cycle`, com zero para os registos anteriores. Substitui a unicidade pagamento/plano por pagamento/plano/ciclo.
4. Substitui a unicidade pagamento/obrigação da afectação pela unicidade decisão/obrigação. A regra de uma ligação activa por pagamento/obrigação mantém-se no motor, dentro do bloqueio organizacional e do pagamento. Só uma reversão confirmada permite nova ligação.
`scripts/reversals-install.php` recusa as bases das demonstrações persistentes, utiliza apenas settings de prova e compara todas as colunas anteriores das nove tabelas antes/depois. As linhas originais coincidiram nas duas composições. O código conserva compatibilidade com o esquema anterior, sem compensações: nesse caso a interface mostra que a actualização ainda não foi aplicada e não oferece os novos formulários.
**Não aplicada em 8005/8006, desenvolvimento ou produção.** Para esses destinos a mudança fica proposta separadamente: inventário e backup/restauro, conferência do esquema exacto, aplicação explícita e outorga dos dois direitos em contexto próprio. Não reverter o esquema simplesmente recriando as unicidades antigas depois de existirem novos ciclos; preservar o ledger e planear recuperação pelo backup ou correcção progressiva. Um binário antigo que desconheça compensações não pode calcular saldos de uma base que já tenha reversões: a versão do pacote e a do esquema têm de ser transportadas em conjunto. Os checkpoints anteriores continuam válidos para os seus esquemas/dados originais. Não há migração de dados reais nesta entrega.
## Provas automáticas
| Etapa | Dívida Compras | Dívida SGF | Pagamento por afectar |
| --- | --- | --- | --- |
| Principal reconhecido | 11 600 MZN | 11 600 MZN | — |
| Pagamento de 4 000 confirmado, antes de afectar | 11 600 MZN | 11 600 MZN | 4 000 MZN |
| Afectação original de 4 000 confirmada | 7 600 MZN | 7 600 MZN | 0 MZN |
| Reversão proposta | 7 600 MZN | 7 600 MZN | 0 MZN |
| Reversão integral confirmada | 11 600 MZN | 11 600 MZN | 4 000 MZN |
| Nova afectação de 3 000 proposta | 11 600 MZN | 11 600 MZN | 4 000 MZN |
| Nova afectação de 3 000 confirmada | 8 600 MZN | 8 600 MZN | 1 000 MZN |
Vencimento e dias de atraso permanecem `null`; atraso indeterminado. Base 10 000, imposto documental 1 600 e principal 11 600 preservados, sem recálculo ou nova regra fiscal.
Evidências novas, sem substituir provas aceites:
- `proofs/supplier-reversals-baseline-20261030.json`: percurso anterior HTTP/HTML no código actualizado e esquema anterior, nas duas composições.
- `proofs/supplier-reversals-20261030.json`: compensação/correcção, repetição com mesma/nova chave, dupla reversão sem novo movimento, conteúdo incompatível, motivo em falta, payload parcial recusado, identidades e pessoas distintas, permissões, revogação durante espera, outra empresa, versão antiga/origem alterada, falha antes do evento e recuperação com a mesma chave, saldo disponível, novo ciclo e repetição das referências/decisões antigas, reentrada e histórico.
- Quatro corridas PostgreSQL por host com dois processos e duas esperas observadas: preparação repetida, confirmação com revogação, confirmação repetida e nova afectação repetida. Não é prova de carga ou de todos os escalonamentos.
- Integridade SQL: tentativas de update/delete dos dois novos tipos de registo recusadas; compensações com montante parcial, autor igual ou unidade incompatível recusadas. Originais de pagamento/decisão/afectação/principal comparados por hash. Um evento/outbox por acontecimento; um único movimento de reversão.
- `proofs/supplier-reversals-legacy-regression-20261030.json`: regressão adversarial dos pagamentos/afectações anteriores, incluindo corridas, isolamento, limites e recuperação, sem regravar a prova aceite.
- `proofs/supplier-reversals-verification-20261030.json`: resumo das verificações finais. Baseline no esquema antigo e regressão adversarial no esquema actualizado aprovados; os três artefactos correspondem ao SHA-256 final do mesmo núcleo `4a719ae1456df974877e2555dd6d559f26ebc40b90ae3ff7e11874cfbf2f106b`. Oito corridas de reversão/correcção e doze de regressão financeira, com processos/ligações separados. Os runners terminaram com remoção das suas bases, roles e processos.
Regressões de Compras: **81 testes aprovados, 343 asserções**, SQLite em memória, nos cinco ficheiros SupplierPayableIntegrationTest, ExternalPaymentTest, InvoiceTest, PayableHistoryImportTest e PayablePaymentDecisionTest. PHPStan das três classes comuns alteradas sem erros; Pint aprovado. Builds SGF e Compras aprovados. Regressão de navegação/página inicial aprovada. A suite SGF que recria a base persistente não foi executada: os comandos SGF foram exercitados nos hosts PostgreSQL descartáveis. Sem dependências novas ou alterações de versões.
Uma asserção antiga do script adversarial ainda esperava oferecer um pagamento totalmente afectado no formulário; foi ajustada para a regra de interface já entregue que o omite. Não se alterou o motor para satisfazer essa asserção.
## Repetição e revisão local
Ficheiros alterados em SGF: `packages/payables/bootstrap.php`, `src/SupplierSettlements.php`, `src/SettlementHttp.php`, `ui/settlements.php`, `routes/web.php`, `scripts/settlements-interface-run.py`, `settlements-interface-check.mjs`, `settlements-http-proof.mjs`, `settlements-probe.php` e documentação. Novos: `packages/payables/src/ReversalSchema.php`, `scripts/reversals-install.php`, `scripts/reversals-http-proof.mjs`, este relatório e as quatro provas acima. Em Compras: `routes/web.php`, `docs/desenvolvimento.md` e `docs/orientacoes-continuidade.md`. Os adaptadores financeiros e o motor de obrigações Payables.php não foram duplicados nem alterados.
A comparação com o checkpoint e4f5200 confirmou que as três provas aceites supplier-settlements.json, supplier-settlements-interface-20261030.json e supplier-settlements-consolidation-20261030.json mantêm o conteúdo anterior. Alterações alheias de documentação/publicação de candidatos em Compras foram preservadas.
Na pasta SGF, executar com os binários existentes:
```powershell
& 'C:/laragon/bin/python/python-3.10/python.exe' scripts/settlements-interface-run.py --reversals
& 'C:/laragon/bin/python/python-3.10/python.exe' scripts/settlements-interface-run.py --adversarial --upgraded
```
O runner exige 8007/8008 livres, cria apenas as suas bases/roles descartáveis e remove-as no finally. Não pára 8005/8006. Para manter as interfaces de prova abertas para revisão local, acrescentar `--review` ao primeiro comando; Compras `http://127.0.0.1:8007/demo?next=payments`, SGF `http://127.0.0.1:8008/demo?next=payments`. Ctrl+C termina os servidores e remove os dados dessa execução. As funções sintéticas são Preparação, Validação e Consulta. Depois das provas o cenário estará em 8 600/1 000; o histórico mostra as etapas. Não há credenciais no relatório.
## Limitações separadas
**Visual:** pendente, sem tentativa de navegador nesta entrega, por instrução expressa. HTTP/HTML, sintaxe JS e VM não comprovam cliques, foco, scroll, legibilidade ou ecrã estreito. O bloqueio anterior de política de URL do navegador Windows não foi contornado.
**MFA:** os dois ignorados anteriores, `users with two factor enabled are redirected to two factor challenge` e `security page is displayed`, continuam pendentes. Não estão nos 81 testes afectados executados agora e não constituem falhas do cálculo financeiro provado.
**Âmbito:** apenas reversão integral de uma afectação confirmada e nova afectação. Sem reversão parcial, cancelamento do pagamento, operação bancária, contabilidade, reconciliação, stock/orçamento adicional, importação de históricos ou habilitação pública. A proposta de reversão fica pendente até confirmação; não foi acrescentado circuito de rejeição/cancelamento da proposta. As demonstrações persistentes não receberam a actualização QA. Sem publicação, push ou checkpoint de encerramento. Falta revisão/aceitação do responsável; não se presume aceitação visual ou técnica deste incremento.