213 lines
7.3 KiB
Python
213 lines
7.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Glosario configurable de la clínica (terminología white-label).
|
|
|
|
Solo lee/escribe el parámetro `skeen.glosario` (JSON). No hay modelo propio:
|
|
el pack base y los overrides se resuelven en memoria.
|
|
|
|
Estructura guardada:
|
|
{"pack": "clinica", "overrides": {"patient_singular": "Huésped"}}
|
|
|
|
Resolución:
|
|
terms = PACKS[pack] (o 'clinica' si el pack no existe) + overrides
|
|
|
|
El pack 'custom' es válido: parte del pack 'clinica' y aplica los overrides.
|
|
Así el endpoint siempre devuelve las 24 claves canónicas resueltas.
|
|
"""
|
|
|
|
import json
|
|
|
|
GLOSARIO_KEY = 'skeen.glosario'
|
|
DEFAULT_PACK = 'clinica'
|
|
CUSTOM_PACK = 'custom'
|
|
|
|
# Las 24 claves canónicas, en el orden del brief (contrato del frontend).
|
|
GLOSARIO_KEYS = (
|
|
'patient_singular', 'patient_plural',
|
|
'appointment_singular', 'appointment_plural',
|
|
'visit_singular', 'visit_plural',
|
|
'record_singular', 'record_plural',
|
|
'doctor_singular', 'doctor_plural',
|
|
'staff_singular', 'staff_plural',
|
|
'branch_singular', 'branch_plural',
|
|
'room_singular', 'room_plural',
|
|
'service_singular', 'service_plural',
|
|
'package_singular', 'package_plural',
|
|
'prescription_singular', 'prescription_plural',
|
|
'treatment_singular', 'treatment_plural',
|
|
)
|
|
|
|
# Nombre legible de cada pack para el selector de configuración.
|
|
PACK_LABELS = {
|
|
'clinica': 'Clínica',
|
|
'spa': 'Spa / Wellness',
|
|
'estetica': 'Estética',
|
|
'dental': 'Dental',
|
|
}
|
|
|
|
PACKS = {
|
|
'clinica': {
|
|
'patient_singular': 'Paciente',
|
|
'patient_plural': 'Pacientes',
|
|
'appointment_singular': 'Cita',
|
|
'appointment_plural': 'Citas',
|
|
'visit_singular': 'Visita',
|
|
'visit_plural': 'Visitas',
|
|
'record_singular': 'Expediente',
|
|
'record_plural': 'Expedientes',
|
|
'doctor_singular': 'Médico',
|
|
'doctor_plural': 'Médicos',
|
|
'staff_singular': 'Personal',
|
|
'staff_plural': 'Personal',
|
|
'branch_singular': 'Sucursal',
|
|
'branch_plural': 'Sucursales',
|
|
'room_singular': 'Cabina',
|
|
'room_plural': 'Cabinas',
|
|
'service_singular': 'Servicio',
|
|
'service_plural': 'Servicios',
|
|
'package_singular': 'Paquete',
|
|
'package_plural': 'Paquetes',
|
|
'prescription_singular': 'Receta',
|
|
'prescription_plural': 'Recetas',
|
|
'treatment_singular': 'Tratamiento',
|
|
'treatment_plural': 'Tratamientos',
|
|
},
|
|
'spa': {
|
|
'patient_singular': 'Cliente',
|
|
'patient_plural': 'Clientes',
|
|
'appointment_singular': 'Reserva',
|
|
'appointment_plural': 'Reservas',
|
|
'visit_singular': 'Sesión',
|
|
'visit_plural': 'Sesiones',
|
|
'record_singular': 'Ficha',
|
|
'record_plural': 'Fichas',
|
|
'doctor_singular': 'Terapeuta',
|
|
'doctor_plural': 'Terapeutas',
|
|
'staff_singular': 'Personal',
|
|
'staff_plural': 'Personal',
|
|
'branch_singular': 'Sucursal',
|
|
'branch_plural': 'Sucursales',
|
|
'room_singular': 'Sala',
|
|
'room_plural': 'Salas',
|
|
'service_singular': 'Servicio',
|
|
'service_plural': 'Servicios',
|
|
'package_singular': 'Paquete',
|
|
'package_plural': 'Paquetes',
|
|
'prescription_singular': 'Recomendación',
|
|
'prescription_plural': 'Recomendaciones',
|
|
'treatment_singular': 'Tratamiento',
|
|
'treatment_plural': 'Tratamientos',
|
|
},
|
|
'estetica': {
|
|
'patient_singular': 'Cliente',
|
|
'patient_plural': 'Clientes',
|
|
'appointment_singular': 'Cita',
|
|
'appointment_plural': 'Citas',
|
|
'visit_singular': 'Sesión',
|
|
'visit_plural': 'Sesiones',
|
|
'record_singular': 'Ficha',
|
|
'record_plural': 'Fichas',
|
|
'doctor_singular': 'Especialista',
|
|
'doctor_plural': 'Especialistas',
|
|
'staff_singular': 'Personal',
|
|
'staff_plural': 'Personal',
|
|
'branch_singular': 'Sucursal',
|
|
'branch_plural': 'Sucursales',
|
|
'room_singular': 'Cabina',
|
|
'room_plural': 'Cabinas',
|
|
'service_singular': 'Servicio',
|
|
'service_plural': 'Servicios',
|
|
'package_singular': 'Paquete',
|
|
'package_plural': 'Paquetes',
|
|
'prescription_singular': 'Receta',
|
|
'prescription_plural': 'Recetas',
|
|
'treatment_singular': 'Tratamiento',
|
|
'treatment_plural': 'Tratamientos',
|
|
},
|
|
'dental': {
|
|
'patient_singular': 'Paciente',
|
|
'patient_plural': 'Pacientes',
|
|
'appointment_singular': 'Cita',
|
|
'appointment_plural': 'Citas',
|
|
'visit_singular': 'Consulta',
|
|
'visit_plural': 'Consultas',
|
|
'record_singular': 'Expediente',
|
|
'record_plural': 'Expedientes',
|
|
'doctor_singular': 'Odontólogo',
|
|
'doctor_plural': 'Odontólogos',
|
|
'staff_singular': 'Personal',
|
|
'staff_plural': 'Personal',
|
|
'branch_singular': 'Sucursal',
|
|
'branch_plural': 'Sucursales',
|
|
'room_singular': 'Consultorio',
|
|
'room_plural': 'Consultorios',
|
|
'service_singular': 'Tratamiento',
|
|
'service_plural': 'Tratamientos',
|
|
'package_singular': 'Paquete',
|
|
'package_plural': 'Paquetes',
|
|
'prescription_singular': 'Receta',
|
|
'prescription_plural': 'Recetas',
|
|
'treatment_singular': 'Procedimiento',
|
|
'treatment_plural': 'Procedimientos',
|
|
},
|
|
}
|
|
|
|
VALID_PACKS = tuple(PACKS) + (CUSTOM_PACK,)
|
|
|
|
|
|
def pack_terms(pack):
|
|
"""Términos base de un pack (copia). 'custom' parte del pack por defecto."""
|
|
base = PACKS.get(pack) or PACKS[DEFAULT_PACK]
|
|
return dict(base)
|
|
|
|
|
|
def get_config(env):
|
|
"""Config vigente: {'pack': str, 'overrides': {clave: valor}}."""
|
|
raw = env['ir.config_parameter'].sudo().get_param(GLOSARIO_KEY)
|
|
pack = DEFAULT_PACK
|
|
overrides = {}
|
|
if raw:
|
|
try:
|
|
guardado = json.loads(raw)
|
|
except (ValueError, TypeError):
|
|
guardado = None
|
|
if isinstance(guardado, dict):
|
|
p = guardado.get('pack')
|
|
if isinstance(p, str) and p:
|
|
pack = p
|
|
o = guardado.get('overrides')
|
|
if isinstance(o, dict):
|
|
overrides = {k: str(v) for k, v in o.items()
|
|
if k in GLOSARIO_KEYS and v is not None and str(v).strip()}
|
|
return {'pack': pack, 'overrides': overrides}
|
|
|
|
|
|
def resolve(env):
|
|
"""(pack, terms): las 24 claves resueltas (pack + overrides)."""
|
|
cfg = get_config(env)
|
|
terms = pack_terms(cfg['pack'])
|
|
terms.update(cfg['overrides'])
|
|
return cfg['pack'], terms
|
|
|
|
|
|
def set_config(env, pack=None, overrides=None):
|
|
"""Guarda pack/overrides. None = conserva lo actual."""
|
|
actual = get_config(env)
|
|
nuevo_pack = actual['pack'] if pack is None else (str(pack).strip() or DEFAULT_PACK)
|
|
nuevos_overrides = actual['overrides']
|
|
if overrides is not None:
|
|
if not isinstance(overrides, dict):
|
|
raise ValueError('overrides debe ser un objeto')
|
|
nuevos_overrides = {k: str(v).strip() for k, v in overrides.items()
|
|
if k in GLOSARIO_KEYS and v is not None and str(v).strip()}
|
|
env['ir.config_parameter'].sudo().set_param(
|
|
GLOSARIO_KEY,
|
|
json.dumps({'pack': nuevo_pack, 'overrides': nuevos_overrides},
|
|
ensure_ascii=False))
|
|
return get_config(env)
|
|
|
|
|
|
def list_packs():
|
|
"""Packs disponibles con nombre legible."""
|
|
return [{'code': code, 'name': PACK_LABELS.get(code, code.capitalize())}
|
|
for code in VALID_PACKS]
|