Release v4928.1.4.2 stable

This commit is contained in:
2026-06-09 22:55:58 +01:00
commit 6445044ac6
280 changed files with 41775 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
# ClientFlow v3 — Clientes, documentos e envios
Esta versão separa responsabilidades para evitar que a página da oportunidade fique demasiado pesada.
## Princípio de UI
- **Clientes**: dados fiscais, NIF, morada, contactos e ligação Jasmin.
- **Oportunidades**: estado da potencial compra, produtos, documentos associados e envios.
- **Documentos**: orçamentos e faturas em `commercial_documents`.
- **Envios**: registos Packlink em `shipments`.
## Páginas principais
### `/customers`
Lista clientes locais normalizados, com pesquisa por nome, NIF, email, telefone ou `jasmin_customer_party_key`.
Permite criar uma ficha mínima de cliente com nome e NIF.
### `/customers/{id}`
Ficha completa de cliente:
- nome fiscal;
- NIF;
- email;
- telefone;
- morada fiscal;
- código postal;
- cidade;
- país;
- Jasmin `customerPartyKey`;
- Jasmin ID;
- oportunidades associadas;
- documentos Jasmin;
- envios Packlink.
### `/opportunities/{id}`
A oportunidade mantém apenas um resumo compacto do cliente e um seletor para associar uma ficha local.
Botões operacionais:
- **Criar orçamento**: cria sempre um novo orçamento Jasmin.
- **Converter em fatura**: converte o orçamento ativo/mais recente em fatura.
## Modelo de dados
Novas tabelas/colunas usadas nesta versão:
- `customers`
- `commercial_documents`
- `commercial_document_lines`
- `shipments`
- `opportunities.local_customer_id`
O campo antigo `opportunities.customer_id` é mantido para compatibilidade com dados legados/Chatwoot. A ligação nova e normalizada usa `opportunities.local_customer_id`.
## Fluxo Jasmin validado
1. Cliente associado à oportunidade.
2. `find_or_create_customer_for_opportunity()` usa primeiro o cliente local.
3. NIF é enviado para Jasmin sem prefixo `PT`.
4. Se o cliente não existir no Jasmin, cria cliente com `partyKey = CF{NIF}`.
5. Cria orçamento `ORC / ORC2026`.
6. Para faturar, chama `POST /billing/invoices/fromQuotation/{quotationId}` com body `{}`.
## Regras importantes
- Não enviar `electronicMail` nem `telephone` vazios para Jasmin.
- OData Jasmin deve usar `$top <= 100`.
- Packlink usa API key no header `Authorization`, sem `Bearer`.
- Para cotação Packlink em Portugal, normalizar CP para 4 dígitos.
## Estratégia de refactor
Esta v3 ainda não reescreve o `admin_dashboard.py` totalmente. A prioridade foi criar a camada de domínio e a navegação operacional correta. O próximo passo recomendado é extrair progressivamente:
- `app/admin_ui/pages/customers.py`
- `app/admin_ui/pages/opportunities.py`
- `app/admin_ui/pages/integrations.py`
- `app/admin_ui/components.py`