Médicos: ventas 30d por médico (count, total MXN/USD, pagado tarjeta)
- card_amount en ventas (pagos con terminal física) - Stats por médico vía líneas recetadas, métrica consistente con comisiones - 4 columnas nuevas en la página de Médicos
This commit is contained in:
@@ -13,6 +13,12 @@ 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 fmtUsd = (n: number | null | undefined) =>
|
||||
n == null ? '—' : n.toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
|
||||
|
||||
const Medicos: FC = () => {
|
||||
const [employees, setEmployees] = useState<Doctor[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -89,6 +95,10 @@ const Medicos: FC = () => {
|
||||
<th className="text-left p-3 text-xs font-medium text-theme-muted uppercase hidden md:table-cell">Teléfono</th>
|
||||
<th className="text-left p-3 text-xs font-medium text-theme-muted uppercase hidden lg:table-cell">Email</th>
|
||||
<th className="text-left p-3 text-xs font-medium text-theme-muted uppercase">% Comisión</th>
|
||||
<th className="text-right p-3 text-xs font-medium text-theme-muted uppercase" title="Ventas con líneas recetadas por el médico, últimos 30 días">Ventas 30d</th>
|
||||
<th className="text-right p-3 text-xs font-medium text-theme-muted uppercase hidden md:table-cell" title="Subtotal de líneas recetadas, últimos 30 días">Total 30d</th>
|
||||
<th className="text-right p-3 text-xs font-medium text-theme-muted uppercase hidden lg:table-cell" title="Equivalente en USD al TC vigente">Total USD</th>
|
||||
<th className="text-right p-3 text-xs font-medium text-theme-muted uppercase hidden md:table-cell" title="Pagado con tarjeta (terminal física), últimos 30 días">Pagado tarjeta</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y">
|
||||
@@ -134,6 +144,10 @@ const Medicos: FC = () => {
|
||||
</Button>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-3 text-sm text-right font-medium text-theme-heading">{d.ventas_30d ?? 0}</td>
|
||||
<td className="p-3 text-sm text-right text-theme-heading hidden md:table-cell">{fmtMoney(d.total_30d ?? 0)}</td>
|
||||
<td className="p-3 text-sm text-right text-theme-muted hidden lg:table-cell">{fmtUsd(d.total_30d_usd)}</td>
|
||||
<td className="p-3 text-sm text-right text-theme-heading hidden md:table-cell">{fmtMoney(d.card_30d ?? 0)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -155,6 +169,10 @@ 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) },
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -250,6 +250,10 @@ export interface Doctor {
|
||||
work_email: string;
|
||||
commission_pct: number;
|
||||
patient_count?: number;
|
||||
ventas_30d?: number;
|
||||
total_30d?: number;
|
||||
total_30d_usd?: number | null;
|
||||
card_30d?: number;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
|
||||
Reference in New Issue
Block a user