Files
SGF/docs/SGC_INVOICE_ENDPOINT.md
2026-11-11 09:00:17 +02:00

9.3 KiB

Endpoint de facturas SGC — implementação local de10/11/2026

Continuação autorizada: workspace persistente SGC entregue, com intenção, decisão, recibo e recuperação auditados. Reutiliza este endpoint/motor sem novas alterações ao seu writer; ambas as capacidades permanecem desligadas no destino.

Implementação concluída para transporte sintético até factura pendente, reutilizando o controlador/workflow/writer fixados de Compras. Não utiliza IntegrationService legado, tabelas espelho sgc_faturas ou saldo orçamental fictício. Não valida a própria factura, consome orçamento, reconhece obrigações, paga ou contabiliza. O percurso e a instalação8085 permanecem intactos.

Rotas e contrato

bootstrap/app.php regista especificamente routes/sgc.php, preservando routes/api.php legado sem montagem. Só existem:

  • GET /api/v1/integration/sgc/invoices/orders/{order}: ordem exacta autorizada, linhas, versão actual e progresso da recepção. Não escolhe uma ordem/linha nem devolve a lista de outras facturas.
  • POST /api/v1/integration/sgc/invoices: fases preview e confirm no mesmo endereço. A confirmação cria apenas a factura pendente; a revisão distinta continua no percurso existente.

Ambas exigem Authorization: Bearer …, X-SGC-Client, X-SGC-Context e Accept: application/json. O POST exige Content-Type: application/json e X-Idempotency-Key UUID. HTTP só é admitido em loopback; fora dele é exigido TLS. O adaptador nativo conserva o bloqueio budget-testing e a validação física do cluster/base/role/manifests QA. Não há capacidade operacional/produtiva presumida.

Na prévia enviar phase, order_id, revision, reason e data com número/data/totais/linhas. Valores monetários são strings decimais, não floats. Quantidades, unidade, preço, imposto, total, linhas aceites e origem são conferidos pelo mesmo motor original. Campos desconhecidos, IDs de autoridade no JSON/query, datas inválidas, linhas repetidas/estrangeiras e corpos acima128KiB são recusados. Até50 linhas. Fundamento de10 a2000 caracteres.

A resposta200 apresenta preview cifrada e impact, sem gravar facturas. O integrador deve apresentar/conferir o impacto antes da confirmação individual, sem confirmação automática. Para confirmar enviar somente:

{"phase":"confirm","order_id":123,"preview":"<prévia devolvida>"}

Usar a mesma chave UUID da prévia. Uma confirmação válida devolve201 com invoice_id, order_id, status: pending, replayed: false. Alteração da versão/origem/contexto exige nova conferência, não uma nova tentativa automática de escrever.

tests/payloads/invoice_test.json é um modelo: os placeholders de ordem/linha/revisão têm de ser substituídos depois de escolha explícita e GET autenticado.100MZN/1UN/imposto0 são apenas o exemplo QA; não são preenchidos automaticamente a partir de uma entidade real. No PowerShell, gerar a chave com [guid]::NewGuid().ToString(); não pressupor uuidgen.

Autenticação e isolamento

config/sgc_invoice.php conserva enabled=false e principals=[]. Nenhuma credencial, associação, concessão ou activação foi instalada. Uma futura configuração exige aprovação própria; o nome do cliente não concede direitos.

Cada principal configurado separadamente contém enabled, SHA256 de um bearer aleatório de pelo menos32 caracteres, user_id, auth_version, tenant_id, company_id, unit_id e context_version de64 hexadecimais. O token nunca é aceite por query/cookie, guardado em log ou distribuído no código. X-SGC-Context deve corresponder à versão configurada; rodar essa versão invalida as prévias antigas. A versão de autenticação deve coincidir com a pessoa actual.

Empresa/unidade/pessoa provêm exclusivamente dessa configuração no servidor. Filiação, empresa/unidade, módulo disponível e direitos existentes são revalidados. Reutilizam-se company.view, unit.view, purchasing_invoices.view/prepare e as funções/autoridades nativas. Nenhum nome de direito novo e nenhuma concessão real. O contexto usa sessão efémera em memória, é limpo ao terminar e não é persistido em cookies/sessões/cache. As respostas de sucesso são no-store, private.

Idempotência, transacção e recuperação

O adaptador serializa cada UUID com advisory lock transaccional PostgreSQL no host, abrangendo a consulta de recuperação e o commit nativo. A chave é normalizada para minúsculas. O recibo autoritativo é o evento append-only já existente sgf.invoice.command, gravado na mesma transacção da factura e das linhas no livro nativo. Não há recibo externo ou espelho de dívida no host.

Antes de uma recuperação, revalidam-se identidade, contexto, direitos, binding actual e visibilidade exacta da ordem. A mesma chave com fundamento/dados/outra ordem gera409; a mesma intenção confirmada devolve200 e o mesmo invoice_id, sem nova factura/auditoria. A recuperação pode ser pedida com a confirmação original ou repetindo a prévia original. A versão de leitura antiga não é uma autorização para outra escrita.

Uma prévia não aplicada expira em600s. Um recibo já confirmado pode ser recuperado depois desse prazo, com a autoridade actual e sem repetir comandos. Rodar contexto/binding ou revogar acesso impede a recuperação pela prévia antiga. Uma falha depois de criar a factura e antes do recibo reverte tudo; a mesma operação pode ser retomada. Se o commit tiver resultado incerto, repetir a mesma chave e conteúdo, sem mudar de número ou inventar nova chave.

Bloqueio da chave acima5s devolve503 RETRY_SAME_KEY, com Retry-After: 1. Recusas de versão/conteúdo:409; validação:422; credencial:401; autoridade:403; configuração desligada:404. Deadlock/serialização também devolvem503 recuperável, sem tratar como sucesso. A duração máxima de todos os possíveis bloqueios nativos/carga sustentada não foi validada.

Provas sintéticas e preservação

78 verificações:42 do percurso/validações/atomicidade/concorrência,20 de revogação/isolamento/recuperação de bloqueio,10 da consulta autenticada/compatibilidade de repetição e seis da autoridade nativa na recuperação. Foram executadas pelo kernel HTTP Laravel com PostgreSQL real e processos PHP independentes, sem criar servidor/porta/base/role/demonstração. Não são testes TCP no portal, revisão visual ou implantação.

Livro de regressão existente receipt-composition-da77bb730751, separado de8085. O cenário original tinha a recepção integralmente facturada; a primeira prévia foi correctamente recusada. Foi então acrescentada uma fixture SQL de origem, marcada fixture_only: cópias de requisição/linha/proposta/adjudicação/ordem/recepção aceite e evento de admissão de teste. Essa preparação não prova uma nova execução desses workflows nem um movimento físico. Facturas/linhas/recibos de comando, por sua vez, passaram pelo motor original: quatro novas facturas pendentes, nenhum consumo/obrigação/pagamento/lançamento novo. Registos originais e provas aceites preservados.

Concorrência da mesma chave:201/200, um invoice_id. Falha injectada no evento imediatamente após o writer:500, sem factura parcial; nova confirmação da mesma intenção:201. Bloqueio da chave mantido por outra ligação:503 após o limite; depois da libertação:200 com a factura original. Conteúdo diferente, versão desactualizada, prévia adulterada, outra ordem/tenant/empresa/unidade, permissões revogadas, token/contexto rodados e módulo indisponível foram recusados.

Comparação de todas as linhas e sequências do host/livro de8085 antes/depois: idênticas. Todas as linhas/sequências/permissões/orçamento do host de regressão também idênticas. Nenhuma ligação de escrita a55432 ou à base da demonstração8039; seis associações protegidas e cache bloqueada não foram alteradas/limpas. Dados de autenticação, cut cifrado, logs e resultados detalhados permanecem privados fora do repositório. Sem checkpoint, publicação ou activação.

Depois das primeiras72 provas, a conferência do operador no caminho de recuperação foi reforçada com o mesmo CurrentActor::lock e a recusa de operador limitado a manutenção. As seis verificações adicionais cobrem essa alteração sem repetir as escritas: função financeira revogada dentro de transacção QA/rollback e manutenção injectada no harness recusam a recuperação; autoridade válida recupera o mesmo recibo. A inclusão da consulta autenticada foi coberta por dez verificações próprias; provas anteriores não foram sobrescritas nem suites alheias repetidas.

node scripts/sgc-invoice-check.mjs apenas consulta o resultado válido, sem repetir ensaios. --new executa outra prova no mesmo livro de regressão existente e acrescenta novas fixtures/documentos QA; usar apenas perante alteração/falha relevante e com o cluster próprio disponível. Não modifica8085 nem instala o endpoint lá.

Prova consolidada. Mantêm-se pendentes activação aprovada/configuração de clientes, utilização real, transporte TLS operacional, política de rotação/rate limiting em implantação, carga sustentada e capacidade de implantação. O serviço legado e os endpoints de pagamentos/analytics continuam fora deste recorte e sem montagem.