Files
SGF/docs/SERVICE_RECEIVABLES_DELIVERY.md
2026-10-27 12:26:52 +02:00

132 lines
18 KiB
Markdown

# SGF-RECEIVABLES-SIM-v1 — entrega técnica isolada
27/10/2026, Africa/Johannesburg. Implementação do âmbito aprovado na secção 12 de [SERVICE_RECEIVABLES_SCOPE.md](SERVICE_RECEIVABLES_SCOPE.md). **Pronto para revisão do utilizador; não constitui aceitação.** Preservados `4276aca` e alterações posteriores. Sem novo checkpoint ou publicação.
## Funcional
- Obrigação explícita sobre ID exacto de documento sintético `si_invoices`, com fotografia e moeda preservadas; documento existente não cria dívida automaticamente. Rascunho/B1 não são origens aceites.
- Propostas imutáveis de obrigação, recebimento, observação e correcção. Cada decisão exige versão exacta e revisão actual da obrigação; confirmação/aprovação por identidade distinta do proponente. Propostas não são editadas: mudança exige nova proposta/revisão, conservando a anterior. Versões não suportadas são recusadas.
- Recebimento confirmado não afecta automaticamente o documento nem comprova reconciliação. Afectação exige comando próprio, saldo disponível e saldo do documento suficientes, na mesma empresa/unidade/cliente/moeda.
- Montantes exactos MZN, sem float ou truncagem: quantias precisam de ser exactamente representáveis a duas casas e respeitar o limite técnico. A base de dados recusa fracções adicionais antes de qualquer arredondamento de coluna. O motor fiscal existente não foi alterado.
- Excesso integral preservado por afectar. Sobreafectação recusada por inteiro; sem crédito, receita, reembolso ou adiantamento automático.
- Saldo, recebido, afectado e disponível derivados do histórico. Vencimento desconhecido não produz atraso; vencido apenas no dia posterior ao vencimento conhecido. Liquidação e reconciliação são dimensões distintas.
- Reconciliação 1:1 exclusivamente simulada, exacta, com observações independentes e identidades explícitas. Divergência permanece registada, sem tolerância; observação não cria recebimento. Reutilização indevida de observação/recebimento conferidos é recusada.
- Reversões integrais por proposta e aprovação; original preservado. Reverter recebimento exige antes libertar afectações e conferência activas, por operações explícitas. Redução sintética identifica documento `TEST-REDUCTION-...`, linha 1 e original. Redução acima do saldo é recusada; não modifica factura ou pedido fiscal de correcção.
- Comprovativo interno apenas no navegador, com origem, data de corte, revisão, valores e efeitos. Avisos permanentes **TESTE — SEM VALIDADE FISCAL** e **SIMULAÇÃO — SEM MOVIMENTAÇÃO DE DINHEIRO**. Não cria recibo fiscal nem novo PDF de recebimento.
## Protecção e persistência
`ServiceReceivables::guard()` recusa execução fora de `testing`/`browser-testing` e executa `TestingDatabaseGuard`: destino efectivo `sgf_tempo_test`, cluster 127.0.0.1:55432, utilizador de testes próprio. A consulta normal devolve bloqueio e listas vazias sem depender das novas tabelas. Não existe flag de activação real.
Todos os INSERT nas seis tabelas novas têm também trigger que recusa uma base diferente de `sgf_tempo_test` ou porta diferente de 55432. Relações de documento, cliente, unidade e moeda são validadas na base; UPDATE/DELETE em massa recusados nos registos de história. Guardas de agregado e revisão serializam escritores por empresa, incluindo INSERT directo em SQL. Não se declara RLS ou autenticação de utilizador final por SQL: a autorização por sessão/contexto/direitos é revalidada no servidor, e a ligação administrativa continua uma fronteira distinta.
Comando, efeito, auditoria, evento e outbox ficam na mesma transacção. Chave por empresa/unidade/actor/acção, hash canónico e unicidades de acontecimento protegem repetições e nova chave sobre a mesma origem. Replay exige direito actual; não reaplica uma afectação entretanto revertida. Consumidor interno `simulation_integrity_v1` marca entrega idempotente em tabela separada e verifica integridade; não contabiliza nem comunica com bancos.
A consulta bloqueia brevemente a linha da empresa para compor uma vista coerente. Todos os escritores usam a mesma ordem de bloqueio. É uma escolha limitada ao incremento local, com serialização ampla; não é promessa de escala para produção. Formulário antigo recebe conflito, exige actualização explícita e não grava sobre a revisão nova.
## Provas e resultados
Ver [resultado do navegador](proofs/receivables-browser-results.json), [imagem](proofs/receivables-browser.png), [concorrência](proofs/receivables-concurrency.json) e [resultado agregado dos testes](proofs/receivables-tests.json).
Prova principal efectuada com login real no Edge, sessão/cache isolados, CSRF activo, `http://127.0.0.1:8001` e exclusivamente `sgf_tempo_test`. Não se usou `actingAs` para demonstrar entrada. As duas identidades sintéticas têm as funções equivalentes à matriz aprovada, sem poderes derivados dos nomes.
| Momento observado no navegador | Recebido | Afectado | Por afectar | Saldo do documento |
| --- | ---: | ---: | ---: | ---: |
| Obrigação confirmada | 0,00 | 0,00 | 0,00 | 1 000,00 |
| Dois recebimentos confirmados, antes das afectações | 1 000,00 | 0,00 | 1 000,00 | 1 000,00 |
| Afectação de 400 | 1 000,00 | 400,00 | 600,00 | 600,00 |
| Afectação adicional de 600, antes da conferência | 1 000,00 | 1 000,00 | 0,00 | 0,00 |
| Duas observações conferidas em simulação | 1 000,00 | 1 000,00 | 0,00 | 0,00 |
O documento sintético de 1 000,00 foi produzido pelo percurso de emissão já aceite, parametrizando apenas a fixture: preço sem imposto 862,07 + IVA de ensaio documental 137,93 = 1 000,00. Não foi atribuída taxa zero nem alterado o motor fiscal. Isso prepara a origem do ensaio; não valida tributação real.
Os testes abrangem ainda: 400+500 após redução sintética de 100; excesso de 100 por afectar; divergência de 0,01; reversões dependentes e repetidas; redução depois de liquidação; observação repetida/reutilizada; escala/limites, datas/vencimento, evidência ausente, origem e IDs manipulados, separação de autores, consulta sem alteração, revogação, contexto antigo, empresa irmã, unidade não autorizada e SQL em massa. Falhas injectadas no outbox desfazem também o efeito financeiro; resposta perdida recupera o mesmo resultado. Falha e repetição da entrega interna não duplicam efeitos.
Seis cenários com dois processos realmente sobrepostos: mesma confirmação produz um efeito e um replay; 400+700 disputando saldo de 1 000; duas afectações disputando o disponível de um recebimento; escritores SQL concorrentes; reversão versus conferência; duas reduções sobre a mesma revisão. Conflitos não repartem valores silenciosamente e não produzem saldo negativo. A prova SQL insere deliberadamente efeitos sintéticos directamente, apenas para verificar as guardas; não representa um comando autorizado de aplicação ou fluxo com auditoria completo.
Resultado final: **39 testes, 711 asserções, zero falhas/erros**; compilação **Vite 8.3.5 aprovada**, sem alteração de dependências. Filtro relevante: `ServiceReceivablesTest|ServiceInvoiceTest|InternalConfirmationTest|DatabaseSafetyTest`. A instância do navegador foi parada antes da regressão final; essa regressão recria apenas a base de testes. As imagens/resultados permanecem; os IDs da demonstração não são garantidos numa repetição. A revisão final reforçou a resolução do cliente pela versão imutável em `a_history` e fixou hash/referência de origem nos novos registos; não depende do rascunho actual. Proposta recusada permanece sem obrigação aberta e sem efeito de atraso.
## Percurso exacto para repetir no navegador
Com autorização de demonstração sintética, preparar a base de testes pelo comando de testes abaixo e garantir que não existe outra prova activa. Os preparadores recusam fixtures preenchidas: não apagam dados para conseguir continuar. Se a porta 8001 estiver ocupada, parar e identificar; nunca terminar processos de outro projecto.
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/sgf.ps1 test '--filter=ServiceReceivablesTest|ServiceInvoiceTest|InternalConfirmationTest|DatabaseSafetyTest'
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/sgf.ps1 npm run build
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/browser-proof.ps1 start
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/sgf.ps1 php scripts/receivables-fixture.php --env=testing
```
Credenciais aleatórias apenas no ficheiro local protegido já usado pelo preparador, nunca no relatório/chat. Não usar contas reais na instância de prova.
1. Entrar como gestor sintético, seleccionar **Empresa Horizonte — Demonstração → Unidade Central — Demonstração → Recebimentos simulados**.
2. Escolher documento exacto `TEST-SERIE-ISOLADA/1`, montante 1 000,00; **Propor obrigação**, com vencimento vazio para provar a pendência.
3. Sair e entrar como validador sintético; seleccionar mesmo contexto; **Confirmar proposta** da obrigação. O proponente não pode confirmar a sua proposta.
4. Voltar ao gestor e propor recebimentos **400.00** e **600.00**, cada um com data declarada não futura, ID de acontecimento diferente e evidência explicitamente artificial. Voltar ao validador e confirmar cada proposta. O saldo continua 1 000 até haver afectação.
5. Voltar ao gestor e **Afectar explicitamente** 400 e 600 nos respectivos recebimentos. Conferir saldo zero, disponível zero e ambos ainda sem reconciliação simulada.
6. Preparar duas observações artificiais, escolhendo o recebimento exacto em cada uma, valores 400/600, datas, IDs de observação distintos e evidências de fonte simulada.
7. Voltar ao validador e **Conferir correspondência exacta** em cada observação. Abrir **Consultar comprovativo interno** e verificar referência documental, montantes, revisão, autores e avisos. Nenhuma descarga de recibo/PDF novo.
8. Para os cenários concorrentes independentes: `sgf.ps1 php scripts/receivables-concurrency.php --env=testing`; para verificar/guardar o agregado do caso principal e entregar eventos internamente: `sgf.ps1 php scripts/receivables-proof.php --env=testing`. Não executar concorrência contra a obrigação principal.
9. Terminar com `powershell -NoProfile -ExecutionPolicy Bypass -File scripts/browser-proof.ps1 stop` antes de voltar a executar testes destrutivos. A aplicação normal conserva a sua ligação.
## Delta aditivo — NÃO aplicado em desenvolvimento
Migração **`2026_10_27_070000_create_simulated_receivables.php`**, com SQL em `database/sql/receivables.sql`. `migrate:status` consultado em `sgf_tempo_dev` confirmou **Pending**. Foi aplicada/recriada apenas pela suite em `sgf_tempo_test`.
Cria seis tabelas:
| Tabela | Finalidade |
| --- | --- |
| `sr_records` | Propostas/documentos sintéticos e referências imutáveis de obrigação, recebimento, observação e correcção |
| `sr_effects` | Decisões, afectações, reconciliações, reduções e compensações imutáveis |
| `sr_commands` | Idempotência e resultado recuperável |
| `sr_events` | Evento versionado por comando, com origem/correlação |
| `sr_outbox` | Captura durável apenas de simulação |
| `sr_deliveries` | Marca imutável de entrega do consumidor interno idempotente |
Acrescenta FKs, índices de unicidade, CHECKs, funções/triggers próprios para relações, precisão, saldos, revisões, separação de autores e imutabilidade. Amplia o CHECK de `permission_grants` com sete nomes de acção exclusivamente de unidade; **não atribui direitos** nem altera alternativas anteriores. Não modifica documentos/B1/cálculos/catálogos ou as tabelas `si_*`. `down()` recusa destruição de história; sem reset/fresh ou rollback destrutivo em desenvolvimento.
**Proposta pendente, a confirmar antes de executar:** aplicar exclusivamente este delta em `sgf_tempo_dev`, preservando dados/acessos, com comparação de integridade antes/depois. Não executado. Mesmo instalada em desenvolvimento, a guarda de aplicação e os triggers impedem INSERT operacional deste ensaio nessa base. Não é proposta de activação real.
## Oito concessões — proposta separada, NÃO aplicada
Contas/âmbito conferidos por leitura através de `scripts/receivables-grants-preview.php`, que não tem modo de aplicação. Tenant #1, **Tempo Lda, empresa #1 / SEGI, unidade #1**, sem extensão a outra unidade. Todos os oito direitos estavam ausentes nessa conferência.
| Conta existente | Novas permissões propostas, prefixo `service_receivables.` | Quantidade |
| --- | --- | ---: |
| #1 — Osmane Nala, nala@tempo.co.mz | `view`, `prepare`, `allocate`, `correction_request` | 4 |
| #2 — Samira Nal, onala@me.com | `view`, `confirm`, `reconcile`, `correction_approve` | 4 |
Exigem confirmação específica antes da aplicação, separada da migração. Sem gestão destes acessos, herança, emissão, banco, reconhecimento ou fecho. Não foram aplicadas às contas reais; apenas equivalentes sintéticos receberam direitos na fixture de testes. Uma eventual concessão local não permite executar recebimentos reais nem contornar o bloqueio.
## Aceitação posterior — 27/10/2026
Entrega isolada encerrada por aceitação do utilizador, registada em [SERVICE_RECEIVABLES_ACCEPTANCE.md](SERVICE_RECEIVABLES_ACCEPTANCE.md), com checkpoint exclusivamente local. As referências anteriores a aceitação pendente descrevem o estado da entrega técnica antes deste encerramento. `070000` e as oito concessões permanecem por aplicar; os bloqueios operacionais e fiscais mantêm-se. Oficinas não exige nova aprovação e custos industriais não foram implementados.
## Instalação técnica especificamente autorizada — 27/10/2026
Após autorização expressa, foi aplicada **apenas** `2026_10_27_070000_create_simulated_receivables` em `sgf_tempo_dev`, por caminho explícito, com o proprietário separado `sgf_dev_owner`. Acrescentou-se exactamente essa entrada no registo de migrações. Não se reaplicou ou alterou a instalação de oficinas `080000`. As referências anteriores a migração/concessões pendentes descrevem o estado anterior a esta autorização.
Aplicadas exactamente oito concessões, todas tenant #1 / Tempo Lda #1 / SEGI #1:
| Conta existente | Direitos, prefixo `service_receivables.` |
| --- | --- |
| Osmane #1 | `view`, `prepare`, `allocate`, `correction_request` |
| Samira #2 | `view`, `confirm`, `reconcile`, `correction_approve` |
Cada concessão tem evento de auditoria. Não se criaram contas, direitos de gestão ou concessões para técnico/verificador. Impressões comparadas apenas em memória confirmaram a preservação dos registos das **54 tabelas preexistentes**, incluindo acessos, auditoria e oficinas. Os únicos novos registos são uma entrada de migração, oito concessões e oito eventos de auditoria; as seis tabelas novas estão vazias.
Procedimento: `scripts/receivables-dev-install.php`, dirigido à operação exacta e deliberadamente recusado se já instalada ou se contas/âmbitos/estado diferirem. Resumo local em `storage/app/private/receivables-dev-install-proof.json`, excluído do Git, sem conteúdos dos registos ou credenciais. A aplicação continua ligada como `sgf_dev_app`, sem privilégios de proprietário/administração.
Conferências no ambiente normal: listagens de recebimentos de ambas as contas bloqueadas/vazias; guarda, proposta, decisão, afectação e consumidor de eventos recusados com 403; listagem/guarda de oficinas e guarda de emissão real igualmente bloqueadas. As funções SQL de ambiente de recebimentos e oficinas recusaram `sgf_tempo_dev`. Código funcional/guardas inalterados. Não se criaram operações reais ou demonstrações na base normal. Não se repetiram testes destrutivos, compilação ou demonstração aceite por uma instalação sem alteração funcional.
Checkpoint aceite `7628645` preservado. Esta instalação técnica não activa recebimentos reais, reconciliação bancária, emissão fiscal, lançamentos, fecho ou publicação, nem altera as aprovações existentes.
## Ficheiros e limites
Código novo: `app/Modules/Services/ServiceReceivables.php`, `Http/ServiceReceivablesController.php`, `resources/js/ServiceReceivablesWorkspace.jsx`; integração em `routes/web.php` e `resources/js/app.jsx`. Migração/SQL acima. Testes e fixtures: `tests/Feature/ServiceReceivablesTest.php`, `tests/Support/ReceivablesFixture.php`; `InvoiceFixture` ganhou parâmetro de preço com valor anterior preservado por omissão. Scripts: `receivables-fixture.php`, `receivables-worker.php`, `receivables-concurrency.php`, `receivables-proof.php`, `receivables-grants-preview.php`. Documentação e provas referidas neste relatório.
Sem dependências/ferramentas novas. Não se modificou o motor exacto, `ServiceInvoicing::guard()`, fotografias B1 ou aprovações existentes. Não se repetiu investigação fiscal do InvesteMoz nem se lhe acedeu neste incremento. Nenhum dado de demonstração entrou na base normal; migração e direitos novos permanecem pendentes. Não foi produzido recibo fiscal, PDF de recebimento, movimento de dinheiro, lançamento, fecho ou comunicação externa.
Limites deliberados: uma moeda MZN, uma linha e obrigação por documento, um documento por recebimento, conferência integral 1:1, reversões integrais, sem edição de propostas/efeitos confirmados, sem câmbio/adiantamentos/retenções/descontos/reembolso. Uma operação que precise de extensão é recusada; não se finge que cabe no caso simples. Conformidade e emissão/configuração reais continuam bloqueadas. Entrega técnica não significa aceitação do utilizador ou autorização do incremento seguinte.