diff --git a/frontend/src/pages/Agenda.tsx b/frontend/src/pages/Agenda.tsx index f08da21..6eeea9b 100644 --- a/frontend/src/pages/Agenda.tsx +++ b/frontend/src/pages/Agenda.tsx @@ -183,6 +183,25 @@ const Agenda: FC = () => { return 'Sin confirmar por teléfono'; }; + // ---- Sala de espera: citas con check-in (2da confirmación) por atender ---- + // Para rol medico el servidor ya devuelve solo sus citas; para recepción/admin + // se respeta el filtro de médico seleccionado (filteredAppointments). + const waitSortKey = (a: Appointment) => a.arrived_at || `9999-12-31 ${a.time}`; + const waitingAppointments = filteredAppointments + .filter((a) => a.state === 'arrived') + .sort((a, b) => waitSortKey(a).localeCompare(waitSortKey(b))); + + // arrived_at viene en UTC (datetime de Odoo) + const waitLabel = (apt: Appointment): string | null => { + if (!apt.arrived_at) return null; + const arrived = new Date(`${apt.arrived_at.replace(' ', 'T')}Z`); + if (Number.isNaN(arrived.getTime())) return null; + const mins = Math.max(0, Math.round((Date.now() - arrived.getTime()) / 60000)); + if (mins < 1) return 'Recién llegó'; + if (mins < 60) return `${mins} min en espera`; + return `${Math.floor(mins / 60)} h ${String(mins % 60).padStart(2, '0')} min en espera`; + }; + // ---- Vista por médico (grid doctores x bloques de 15 min) ---- const GRID_START = 8; // horario clínica: 8:00 const GRID_END = 19; // horario clínica: 19:00 (último bloque inicia 18:45) @@ -944,6 +963,37 @@ const Agenda: FC = () => { )} + {/* Sala de espera: pacientes con check-in (2da confirmación) por atender */} +
Por atender
+ + {waitingAppointments.length} + +Sin pacientes en espera.
+ ) : ( +{error}
} {loading ? ( diff --git a/frontend/src/services/odoo.ts b/frontend/src/services/odoo.ts index 27148af..d562dac 100644 --- a/frontend/src/services/odoo.ts +++ b/frontend/src/services/odoo.ts @@ -72,6 +72,8 @@ export interface Appointment { phone_confirmed?: boolean; phone_confirmed_at?: string | null; phone_confirmed_by?: string | null; + // Timestamp del check-in de llegada (2da confirmación) + arrived_at?: string | null; } export interface Bloqueo { diff --git a/odoo-addons/skeen_citas/models/cita.py b/odoo-addons/skeen_citas/models/cita.py index 20d68cd..b00f15f 100644 --- a/odoo-addons/skeen_citas/models/cita.py +++ b/odoo-addons/skeen_citas/models/cita.py @@ -133,6 +133,8 @@ class SkeenCita(models.Model): phone_confirmed_at = fields.Datetime(string='Fecha Confirmación Tel.', readonly=True, copy=False) phone_confirmed_by = fields.Char(string='Confirmada por', readonly=True, copy=False, help='Login del usuario del frontend que confirmó por teléfono') + # Timestamp del check-in de llegada (2da confirmación); base del tiempo de espera + arrived_at = fields.Datetime(string='Hora de Llegada', readonly=True, copy=False) # Pago payment_state = fields.Selection([ @@ -182,7 +184,7 @@ class SkeenCita(models.Model): self.write({'state': 'confirmed'}) def action_arrive(self): - self.write({'state': 'arrived'}) + self.write({'state': 'arrived', 'arrived_at': fields.Datetime.now()}) def action_start(self): self.write({'state': 'in_progress'}) diff --git a/odoo-addons/skeen_whatsapp/controllers/frontend.py b/odoo-addons/skeen_whatsapp/controllers/frontend.py index faa5b94..e8a61ab 100644 --- a/odoo-addons/skeen_whatsapp/controllers/frontend.py +++ b/odoo-addons/skeen_whatsapp/controllers/frontend.py @@ -776,6 +776,8 @@ class SkeenFrontendController(http.Controller): 'phone_confirmed': cita.phone_confirmed, 'phone_confirmed_at': cita.phone_confirmed_at.strftime('%Y-%m-%d %H:%M') if cita.phone_confirmed_at else None, 'phone_confirmed_by': cita.phone_confirmed_by or None, + # 2da confirmación: timestamp del check-in (base del tiempo de espera) + 'arrived_at': cita.arrived_at.strftime('%Y-%m-%d %H:%M:%S') if cita.arrived_at else None, } # ============================================================