Import ClientFlow production v4928.1.5.132.4

This commit is contained in:
plx
2026-07-29 13:11:01 +00:00
parent 6445044ac6
commit 261d342057
405 changed files with 48373 additions and 1401 deletions

View File

@@ -52,7 +52,7 @@ router = APIRouter()
TYPE_LABELS = {
"jasmin_quotation": "Orçamento Jasmin",
"jasmin_proforma": "Pró-forma Jasmin",
"jasmin_proforma": "Orçamento Jasmin legado",
"jasmin_invoice": "Fatura Jasmin",
"odoo_sale_order": "Venda Odoo",
"payment_proof": "Comprovativo",
@@ -85,7 +85,7 @@ def _operation_label(value: str | None) -> str:
labels = {
"odoo_sale_order": "Venda Odoo",
"jasmin_quotation": "Orçamento Jasmin",
"jasmin_proforma": "Pró-forma Jasmin",
"jasmin_proforma": "Orçamento Jasmin legado",
"jasmin_invoice": "Fatura Jasmin",
"document": "Documento",
}
@@ -443,8 +443,8 @@ async def reconciliation_page(status: Optional[str] = "open", external_type: Opt
<h2 class="cf-section-title mb-3">Registar pedido externo</h2>
<form method="post" action="/reconciliation/manual-request" class="d-grid gap-3">
<div class="row g-2"><div class="col-md-4"><label class="form-label small fw-bold">Origem</label><select class="form-select" name="source_channel"><option>WhatsApp</option><option>Telefone</option><option>Email direto</option><option>Presencial</option><option>Outro</option></select></div><div class="col-md-8"><label class="form-label small fw-bold">Nome/contacto</label><input class="form-control" name="customer_name" required></div></div>
<div class="row g-2"><div class="col-md-6"><label class="form-label small fw-bold">Email</label><input class="form-control" name="customer_email"></div><div class="col-md-6"><label class="form-label small fw-bold">Telefone</label><input class="form-control" name="customer_phone"></div></div>
<div class="row g-2"><div class="col-md-6"><label class="form-label small fw-bold">Produto/interesse</label><input class="form-control" name="product_interest" placeholder="Carregador EV, Cabo..."></div><div class="col-md-6"><label class="form-label small fw-bold">Próxima ação</label><select class="form-select" name="action_code"><option value="SEND_QUOTE">Preparar orçamento</option><option value="SEND_INFO">Preparar resposta</option><option value="SEND_PROFORMA">Emitir pró-forma</option><option value="SEND_INVOICE">Emitir fatura</option><option value="REVIEW_MANUALLY">Rever manualmente</option></select></div></div>
<div class="row g-2"><div class="col-md-6"><label class="form-label small fw-bold">Email</label><input class="form-control" name="customer_email" type="email" autocomplete="off"></div><div class="col-md-6"><label class="form-label small fw-bold">Telefone</label><input class="form-control" name="customer_phone" type="tel" autocomplete="off"></div></div>
<div class="row g-2"><div class="col-md-6"><label class="form-label small fw-bold">Produto/interesse</label><input class="form-control" name="product_interest" placeholder="Carregador EV, Cabo..."></div><div class="col-md-6"><label class="form-label small fw-bold">Próxima ação</label><select class="form-select" name="action_code"><option value="SEND_QUOTE">Preparar orçamento</option><option value="SEND_INFO">Preparar resposta</option><option value="SEND_PROFORMA">Enviar orçamento para pagamento</option><option value="SEND_INVOICE">Emitir fatura</option><option value="REVIEW_MANUALLY">Rever manualmente</option></select></div></div>
<div><label class="form-label small fw-bold">Mensagem/pedido</label><textarea class="form-control" rows="3" name="request_text" placeholder="Colar texto do WhatsApp, telefone ou email direto..."></textarea></div>
<div><button class="btn btn-primary" type="submit">Guardar e criar oportunidade</button></div>
</form>
@@ -506,6 +506,12 @@ async def reconciliation_sync_odoo(request: Request):
days = _safe_days(form.get("days"), 3)
result = sync_odoo_reconciliation_candidates(limit=50, days=days)
notice = f"Odoo últimos {result.get('days', days)} dias: analisadas {result.get('seen', 0)} vendas · candidatos criados/atualizados {result.get('created_or_updated', 0)}"
if result.get("already_linked"):
notice += f" · já ligadas {result.get('already_linked', 0)}"
if result.get("resolved_existing"):
notice += f" · candidatos obsoletos resolvidos {result.get('resolved_existing', 0)}"
if result.get("link_conflicts"):
notice += f" · conflitos de ligação {result.get('link_conflicts', 0)}"
if result.get("skipped"):
notice += " · " + str(result.get("skipped"))
return RedirectResponse(f"/reconciliation?days={days}&notice={esc(notice)}", status_code=303)