Punto 13: alta/baja de médicos desde el módulo Médicos

- Columna 'Estado' con switch Activo/Baja (confirmación previa) y checkbox
  'Mostrar dados de baja' para poder reactivar.
- GET /doctors solo devuelve activos; include_inactive=1 para la pantalla de
  Médicos. Cada médico expone su campo 'active'.
- Reglas en modelo: un empleado dado de baja no admite citas nuevas
  (skeen.cita), ni asignación de pacientes (res.partner.primary_doctor_id),
  ni líneas de venta (skeen.venta.line.prescribed_by_id). El historial
  existente no se toca: los constraints solo corren cuando cambia la
  asignación.
- ValidationError se responde 400 con mensaje legible en pacientes y ventas.
- fix: badges de estado de cita en agenda y dashboard usan la etiqueta de la
  clínica en lugar del valor técnico.
This commit is contained in:
Kimi
2026-09-24 16:03:02 +00:00
parent d0eac00a40
commit 09b4f25bb8
6 changed files with 146 additions and 10 deletions

View File

@@ -1917,6 +1917,9 @@ class SkeenFrontendController(http.Controller):
vals['image_1920'] = data['photo']
patient = request.env['res.partner'].sudo().create(vals)
return json_response({'status': 'success', 'patient': self._patient_to_dict(patient)}, 201)
except ValidationError as e:
# Reglas de negocio (p. ej. médico dado de baja): mensaje legible
return json_response({'status': 'error', 'message': e.args[0] if e.args else str(e)}, 400)
except Exception as e:
return json_response({'status': 'error', 'message': str(e)}, 500)
@@ -1985,6 +1988,8 @@ class SkeenFrontendController(http.Controller):
# El rastro principal es la auditoría; el chatter es extra
pass
return json_response({'status': 'success', 'patient': self._patient_to_dict(patient)})
except ValidationError as e:
return json_response({'status': 'error', 'message': e.args[0] if e.args else str(e)}, 400)
except Exception as e:
return json_response({'status': 'error', 'message': str(e)}, 500)
@@ -3170,7 +3175,12 @@ class SkeenFrontendController(http.Controller):
# de dinero por médico son del módulo Médicos (admin/recepción).
fu = current_user(request.env)
hide_money = bool(fu and fu.role == 'medico')
doctors = request.env['hr.employee'].sudo().search([('active', '=', True)], limit=100)
# Por defecto solo el personal activo: así desaparecen de la agenda,
# del selector de médico de pacientes y del selector de ventas.
# La pantalla de Médicos pide include_inactive=1 para poder reactivar.
domain = [] if str(kw.get('include_inactive')).lower() in ('1', 'true') else [('active', '=', True)]
doctors = request.env['hr.employee'].sudo().with_context(active_test=False).search(
domain, order='active desc, name', limit=300)
# Pacientes asignados por médico (primary_doctor_id)
counts = {}
for g in request.env['res.partner'].sudo().read_group(
@@ -3237,6 +3247,7 @@ class SkeenFrontendController(http.Controller):
'doctors': [{
'id': d.id,
'name': d.name,
'active': d.active,
'job_title': d.job_title or '',
'work_phone': d.work_phone or '',
'work_email': d.work_email or '',
@@ -3285,6 +3296,10 @@ class SkeenFrontendController(http.Controller):
if data['staff_type'] not in ('doctor', 'cosmetologa'):
return json_response({'status': 'error', 'message': "staff_type debe ser 'doctor' o 'cosmetologa'"}, 400)
vals['staff_type'] = data['staff_type']
if 'active' in data:
# Desactivar oculta al médico de la agenda, de la asignación de
# pacientes y del selector de ventas; no borra su historial.
vals['active'] = bool(data.get('active'))
if vals:
previos = {k: getattr(doctor, k) for k in vals}
doctor.write(vals)
@@ -4012,6 +4027,8 @@ class SkeenFrontendController(http.Controller):
if data.get('state') == 'confirmed':
sale.action_confirm()
return json_response({'status': 'success', 'sale': self._sale_to_dict(sale)}, 201)
except ValidationError as e:
return json_response({'status': 'error', 'message': e.args[0] if e.args else str(e)}, 400)
except Exception as e:
return json_response({'status': 'error', 'message': str(e)}, 500)