diff --git a/frontend/src/pages/Medicos.tsx b/frontend/src/pages/Medicos.tsx index 1c2ec21..1fd1903 100644 --- a/frontend/src/pages/Medicos.tsx +++ b/frontend/src/pages/Medicos.tsx @@ -13,11 +13,41 @@ const isMedicalTitle = (jobTitle?: string) => { return medicalTerms.some((term) => normalized.includes(term)); }; -const fmtMoney = (n: number) => - (n || 0).toLocaleString('es-MX', { style: 'currency', currency: 'MXN', maximumFractionDigits: 0 }); +const fmtNum = (n: number | null | undefined, decimals = 2) => + (n ?? 0).toLocaleString('es-MX', { maximumFractionDigits: decimals }); -const fmtUsd = (n: number | null | undefined) => - n == null ? '—' : n.toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }); +/** Badges de ventas 30d al estilo del sistema legacy: + * píldora verde "N ventas" + gris "N recomendaciones" y + * píldoras índigo apiladas: usd / m.n. / tarjeta m.n. */ +const StatBadges: FC<{ d: Doctor }> = ({ d }) => ( +
+
+ + {d.ventas_30d ?? 0} ventas + + + {d.recomendaciones_30d ?? 0} recomendaciones + +
+
+ + {d.total_30d_usd == null ? '—' : fmtNum(d.total_30d_usd)} usd + + + {fmtNum(d.total_30d ?? 0, 0)} m.n. + + + {fmtNum(d.card_30d ?? 0, 0)} tarjeta m.n. + +
+
+); const Medicos: FC = () => { const [employees, setEmployees] = useState([]); @@ -95,10 +125,7 @@ const Medicos: FC = () => { Teléfono Email % Comisión - Ventas 30d - Total 30d - Total USD - Pagado tarjeta + Últimos 30 días @@ -144,10 +171,9 @@ const Medicos: FC = () => { - {d.ventas_30d ?? 0} - {fmtMoney(d.total_30d ?? 0)} - {fmtUsd(d.total_30d_usd)} - {fmtMoney(d.card_30d ?? 0)} + + + ))} @@ -169,10 +195,7 @@ const Medicos: FC = () => { { label: 'Teléfono', value: d.work_phone || '-' }, { label: 'Email', value: d.work_email || '-' }, { label: '% Comisión', value: `${d.commission_pct ?? 0}%` }, - { label: 'Ventas 30d', value: String(d.ventas_30d ?? 0) }, - { label: 'Total 30d', value: fmtMoney(d.total_30d ?? 0) }, - { label: 'Total USD', value: fmtUsd(d.total_30d_usd) }, - { label: 'Pagado tarjeta', value: fmtMoney(d.card_30d ?? 0) }, + { label: 'Últimos 30 días', value: }, ]} /> ))} diff --git a/frontend/src/services/odoo.ts b/frontend/src/services/odoo.ts index 08fbf45..b143a52 100644 --- a/frontend/src/services/odoo.ts +++ b/frontend/src/services/odoo.ts @@ -250,6 +250,7 @@ export interface Doctor { work_email: string; commission_pct: number; patient_count?: number; + recomendaciones_30d?: number; ventas_30d?: number; total_30d?: number; total_30d_usd?: number | null; diff --git a/odoo-addons/skeen_whatsapp/controllers/frontend.py b/odoo-addons/skeen_whatsapp/controllers/frontend.py index d5e7105..2292e0e 100644 --- a/odoo-addons/skeen_whatsapp/controllers/frontend.py +++ b/odoo-addons/skeen_whatsapp/controllers/frontend.py @@ -1657,6 +1657,16 @@ class SkeenFrontendController(http.Controller): # ---- Ventas de los últimos 30 días por médico ---- since = (date.today() - timedelta(days=30)).strftime('%Y-%m-%d') + + # Recomendaciones: pacientes captados en 30d asignados al médico + # con "recomendado por" capturado (misma métrica visible del legacy) + recomendaciones = {} + for g in request.env['res.partner'].sudo().read_group( + [('is_patient', '=', True), ('primary_doctor_id', 'in', doctors.ids), + ('referred_by', 'not in', [False, '']), ('create_date', '>=', since)], + [], ['primary_doctor_id']): + recomendaciones[g['primary_doctor_id'][0]] = g['primary_doctor_id_count'] + stats = {} # doctor_id -> {'ventas': set, 'total': float} card_by_venta = {} ventas = request.env['skeen.venta'].sudo().search([ @@ -1700,6 +1710,7 @@ class SkeenFrontendController(http.Controller): 'work_email': d.work_email or '', 'commission_pct': d.commission_pct or 0.0, 'patient_count': counts.get(d.id, 0), + 'recomendaciones_30d': recomendaciones.get(d.id, 0), 'ventas_30d': len(stats.get(d.id, {}).get('ventas', set())), 'total_30d': round(stats.get(d.id, {}).get('total', 0.0), 2), 'total_30d_usd': round(stats.get(d.id, {}).get('total', 0.0) / rate, 2) if rate else None,