POS: selector Doctor que atendio para asignar la venta completa a un doctor (comisiones)
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
Skeleton,
|
||||
toast,
|
||||
} from '../components/ui';
|
||||
import { odooApi, type Service, type Patient, type InventoryItem, type PosCheckoutResult } from '../services/odoo';
|
||||
import { odooApi, type Service, type Patient, type InventoryItem, type PosCheckoutResult, type Doctor } from '../services/odoo';
|
||||
|
||||
const fmtMoney = (n: number) =>
|
||||
(n || 0).toLocaleString('es-MX', { style: 'currency', currency: 'MXN', maximumFractionDigits: 2 });
|
||||
@@ -71,6 +71,11 @@ const Pos: FC = () => {
|
||||
const [cobrando, setCobrando] = useState(false);
|
||||
const [tcRate, setTcRate] = useState<number | null>(null);
|
||||
|
||||
// Doctor que atendió/recetó: se aplica como prescribed_by_id a todas las
|
||||
// líneas al cobrar (alimenta "Mis ventas" y comisiones). Opcional.
|
||||
const [doctors, setDoctors] = useState<Doctor[]>([]);
|
||||
const [doctorId, setDoctorId] = useState('');
|
||||
|
||||
// Resultado
|
||||
const [resultado, setResultado] = useState<PosCheckoutResult | null>(null);
|
||||
|
||||
@@ -123,6 +128,13 @@ const Pos: FC = () => {
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
// Doctores activos para el selector "Doctor que atendió"
|
||||
useEffect(() => {
|
||||
odooApi.getDoctors()
|
||||
.then((res) => { if (res.status === 'success') setDoctors(res.doctors); })
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
// Tipo de cambio USD/MXN: al montar y refresco cada 5 min
|
||||
useEffect(() => {
|
||||
const fetchTc = () => {
|
||||
@@ -256,6 +268,8 @@ const Pos: FC = () => {
|
||||
...(l.item_id ? { item_id: l.item_id } : {}),
|
||||
quantity: l.qty,
|
||||
price_unit: l.price,
|
||||
// Asignación a nivel venta: el doctor seleccionado aplica a todas las líneas
|
||||
...(doctorId ? { prescribed_by_id: parseInt(doctorId, 10) } : {}),
|
||||
})),
|
||||
discount: discountNum,
|
||||
payment_method: metodo,
|
||||
@@ -280,12 +294,29 @@ const Pos: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Selector "Doctor que atendió": se comparte entre el ticket y el modal de cobro
|
||||
const doctorBlock = (
|
||||
<Select
|
||||
label="Doctor que atendió"
|
||||
options={[
|
||||
{ value: '', label: 'Sin asignar' },
|
||||
...doctors.map((d) => ({
|
||||
value: String(d.id),
|
||||
label: (d.staff_type ?? 'doctor') === 'cosmetologa' ? `${d.name} (Cosmetóloga)` : d.name,
|
||||
})),
|
||||
]}
|
||||
value={doctorId}
|
||||
onChange={(e) => setDoctorId(e.target.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
const nuevaVenta = () => {
|
||||
setResultado(null);
|
||||
setLines([]);
|
||||
setDiscount('');
|
||||
setPaciente(null);
|
||||
setPacienteQuery('');
|
||||
setDoctorId('');
|
||||
};
|
||||
|
||||
// ---- Bloques del ticket (desktop sticky y modal móvil) ----
|
||||
@@ -435,6 +466,9 @@ const Pos: FC = () => {
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="border border-theme-border rounded-xl p-2.5 bg-theme-bg">
|
||||
{doctorBlock}
|
||||
</div>
|
||||
<Button
|
||||
className="w-full mt-1 !py-3 text-base"
|
||||
onClick={abrirCobro}
|
||||
@@ -633,6 +667,12 @@ const Pos: FC = () => {
|
||||
}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="border border-theme-border rounded-xl p-3 bg-theme-bg">
|
||||
{doctorBlock}
|
||||
<p className="text-xs text-theme-muted mt-1">
|
||||
Se asigna la venta completa a este doctor para sus comisiones.
|
||||
</p>
|
||||
</div>
|
||||
<Select label="Método de pago" options={METODO_OPTIONS} value={metodo} onChange={(e) => setMetodo(e.target.value)} />
|
||||
{metodo === 'cash' && !conPuntos && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user