fase 1 productizacion: capa de configuracion (glosario multi-giro, sucursales y categorias configurables, ajustes de clinica por instancia, colores de marca, horarios, URLs de pago dinamicas) + script de provisioning de instancia nueva con datos demo + frontend consumiendo la config
This commit is contained in:
212
odoo-addons/skeen_citas/glosario.py
Normal file
212
odoo-addons/skeen_citas/glosario.py
Normal file
@@ -0,0 +1,212 @@
|
||||
# -*- 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]
|
||||
Reference in New Issue
Block a user