Oleada B: fusion Expedientes en Pacientes (+chip sin visita 6m), sidebar colapsable SKEEN, edicion completa de citas, autocompletado de paciente, bloqueos excluidos de slots
This commit is contained in:
@@ -265,11 +265,18 @@ class SkeenCita(models.Model):
|
||||
if b.all_day or (ini < b.time_to and fin > b.time_from):
|
||||
raise ValidationError(_('El médico tiene un bloqueo (%s)') % (b.motivo or 'agenda bloqueada'))
|
||||
|
||||
def get_available_slots(self, date, servicio_id):
|
||||
"""Retorna slots disponibles para una fecha y servicio"""
|
||||
def get_available_slots(self, date, servicio_id, doctor_id=None):
|
||||
"""Retorna slots disponibles para una fecha y servicio.
|
||||
Con doctor_id, además excluye los horarios bloqueados de ese médico
|
||||
(el usuario no debe poder elegir una hora bloqueada)."""
|
||||
servicio = self.env['skeen.servicio'].browse(servicio_id)
|
||||
duration = servicio.duration_min if servicio else 30
|
||||
|
||||
# Bloqueos del médico para la fecha (día completo y por rango)
|
||||
bloqueos = self.env['skeen.cita.bloqueo'].search([
|
||||
('date', '=', date),
|
||||
] + ([('doctor_id', '=', doctor_id)] if doctor_id else []))
|
||||
|
||||
# Horario de la clínica: 8:00 AM a 7:00 PM
|
||||
start_time = 8.0 # 8:00 AM
|
||||
end_time = 19.0 # 7:00 PM
|
||||
@@ -289,7 +296,11 @@ class SkeenCita(models.Model):
|
||||
('datetime_start', '<', slot_end),
|
||||
('datetime_end', '>', slot_start),
|
||||
]
|
||||
if not self.search(domain):
|
||||
en_bloqueo = any(
|
||||
b.all_day or (current < b.time_to and current + (duration / 60.0) > b.time_from)
|
||||
for b in bloqueos
|
||||
)
|
||||
if not en_bloqueo and not self.search(domain):
|
||||
slots.append({
|
||||
'time': current,
|
||||
'time_str': f"{int(current):02d}:{minutes:02d}",
|
||||
|
||||
@@ -647,10 +647,11 @@ class SkeenFrontendController(http.Controller):
|
||||
try:
|
||||
date_str = kw.get('date')
|
||||
servicio_id = int(kw.get('servicio_id', 0))
|
||||
doctor_id = int(kw.get('doctor_id', 0)) if kw.get('doctor_id') else None
|
||||
if not date_str or not servicio_id:
|
||||
return json_response({'status': 'error', 'message': 'Falta date o servicio_id'}, 400)
|
||||
d = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
slots = request.env['skeen.cita'].sudo().get_available_slots(d, servicio_id)
|
||||
slots = request.env['skeen.cita'].sudo().get_available_slots(d, servicio_id, doctor_id=doctor_id)
|
||||
return json_response({'status': 'success', 'slots': slots})
|
||||
except Exception as e:
|
||||
return json_response({'status': 'error', 'message': str(e)}, 500)
|
||||
@@ -1085,6 +1086,10 @@ class SkeenFrontendController(http.Controller):
|
||||
if kw.get('recent') == '1':
|
||||
seis_meses = (date.today() - timedelta(days=183)).strftime('%Y-%m-%d')
|
||||
domain.append(('last_visit', '>=', seis_meses))
|
||||
elif kw.get('recent') == '0':
|
||||
# Sin visita en los últimos 6 meses (incluye sin visita registrada)
|
||||
seis_meses = (date.today() - timedelta(days=183)).strftime('%Y-%m-%d')
|
||||
domain += ['|', ('last_visit', '=', False), ('last_visit', '<', seis_meses)]
|
||||
page = max(int(kw.get('page', 1) or 1), 1)
|
||||
page_size = min(max(int(kw.get('page_size', 50) or 50), 1), 200)
|
||||
Pacientes = request.env['res.partner'].sudo()
|
||||
|
||||
@@ -54,7 +54,6 @@ DEFAULT_MENU_ROLES = {
|
||||
'/pos': ['admin', 'recepcion', 'gerencia'],
|
||||
'/visitas': ['admin', 'recepcion', 'medico', 'gerencia'],
|
||||
'/consultas': ['admin', 'recepcion', 'medico', 'gerencia'],
|
||||
'/expedientes': ['admin', 'recepcion', 'medico', 'gerencia'],
|
||||
'/medicos': ['admin', 'recepcion', 'gerencia'],
|
||||
'/servicios': ['admin', 'recepcion', 'medico', 'lectura', 'gerencia'],
|
||||
'/productos': ['admin', 'recepcion', 'lectura', 'gerencia'],
|
||||
|
||||
Reference in New Issue
Block a user