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

55
RELEASE_NOTES_v4926_5.md Normal file
View File

@@ -0,0 +1,55 @@
# ClientFlow v4.9.26.5 — Manual opportunity from fiscal customer
Inclui também a hotfix `v4926.4.1_skip_duplicate_identity_suggestion`.
## Alterações principais
- Página do cliente fiscal passa a ter formulário **Nova oportunidade**.
- Permite criar oportunidade manual por telefone, WhatsApp, email, presencial ou manual.
- A oportunidade nasce já ligada ao `customers.id` fiscal.
- Opcionalmente cria uma task inicial para a próxima ação.
- Guarda snapshot fiscal do cliente na metadata da oportunidade.
- Regista evento `manual_opportunity_created` na timeline da oportunidade.
- O assistente de identidade de email deixa de criar sugestão pendente duplicada quando o cliente sugerido já é o cliente fiscal atual.
- O detalhe da oportunidade mostra mensagem específica quando a identidade extraída confirma o cliente fiscal atual.
## Configuração recomendada
```env
EMAIL_IDENTITY_EXTRACTION_ENABLED=true
EMAIL_IDENTITY_EXTRACTION_USE_LLM=true
EMAIL_IDENTITY_LLM_MODEL=qwen/qwen3-235b-a22b-2507
EMAIL_IDENTITY_LLM_FALLBACK_MODEL=qwen/qwen3-max
EMAIL_IDENTITY_LLM_TIMEOUT_SECONDS=20
EMAIL_IDENTITY_LLM_MAX_BODY_CHARS=3500
```
## Testes manuais recomendados
### Criar oportunidade a partir de cliente fiscal
1. Abrir `/customers`.
2. Abrir uma ficha de cliente.
3. Usar o formulário **Nova oportunidade**.
4. Confirmar que a nova oportunidade abre em `/opportunities/{id}`.
5. Confirmar que o cliente fiscal já está associado.
6. Confirmar que a task inicial aparece quando a checkbox está marcada.
### Validar skip duplicate identity suggestion
```bash
PYTHONPATH=. python - <<'PY'
from app.fiscal_enrichment_service import assist_email_identity_enrichment
print(assist_email_identity_enrichment("OPPORTUNITY_ID", refresh=True, apply_safe=False))
PY
```
Se a identidade extraída apontar para o mesmo cliente fiscal já associado, o esperado é:
```json
{
"suggested": 0,
"skipped": 1,
"status": "email_identity_matches_current_fiscal_customer"
}
```