fase 3.1: recursos fisicos en agenda (modelo skeen.recurso con semilla cabina/consultoria, asignacion multiple a citas con validacion de solape, bloqueos por recurso, lista de espera desde recursos, vista/filtro por recurso, reporte de ocupacion); apagado por defecto
This commit is contained in:
59
odoo-addons/skeen_citas/models/recurso.py
Normal file
59
odoo-addons/skeen_citas/models/recurso.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
# Tipos de recurso físico de la agenda. Los códigos son estables: la lógica
|
||||
# interna solo usa `code`/`tipo` como etiqueta, nunca para decidir solapes.
|
||||
RECURSO_TIPOS = [
|
||||
('cabina', 'Cabina'),
|
||||
('sala', 'Sala'),
|
||||
('consultorio', 'Consultorio'),
|
||||
('equipo', 'Equipo'),
|
||||
('otro', 'Otro'),
|
||||
]
|
||||
|
||||
|
||||
class SkeenRecurso(models.Model):
|
||||
"""Recurso físico que se puede asignar a las citas (cabina, sala, equipo).
|
||||
|
||||
Sustituye a las dos opciones que estaban hardcodeadas en la lista de
|
||||
espera ('cabina'/'consultoria'): los recursos semilla conservan esos
|
||||
códigos para que los registros históricos sigan mostrándose igual.
|
||||
|
||||
`sucursales` vacío = el recurso aplica a todas las sucursales.
|
||||
Todo el módulo queda apagado con `recursos.activo=False` (por defecto):
|
||||
mientras no se active, este catálogo no cambia nada en la agenda.
|
||||
"""
|
||||
_name = 'skeen.recurso'
|
||||
_description = 'Recurso de la agenda (cabina, sala, consultorio, equipo)'
|
||||
_order = 'sequence, name'
|
||||
|
||||
name = fields.Char(string='Nombre', required=True, translate=True)
|
||||
code = fields.Char(string='Código', required=True, copy=False,
|
||||
help='Identificador estable que se guarda en citas y bloqueos.')
|
||||
tipo = fields.Selection(RECURSO_TIPOS, string='Tipo', default='cabina', required=True)
|
||||
activo = fields.Boolean(string='Activo', default=True)
|
||||
sequence = fields.Integer(string='Secuencia', default=10)
|
||||
sucursales = fields.Many2many(
|
||||
'skeen.sucursal', 'skeen_recurso_sucursal_rel', 'recurso_id', 'sucursal_id',
|
||||
string='Sucursales',
|
||||
help='Sucursales donde está disponible. Vacío = todas.')
|
||||
capacidad = fields.Integer(string='Capacidad', default=0)
|
||||
costo_hora = fields.Float(string='Costo por hora', default=0.0,
|
||||
help='Costo operativo del recurso por hora, para estimar ingresos en reportes.')
|
||||
color = fields.Char(string='Color', help='Color hex para distinguirlo en la agenda (p. ej. #1abc9c).')
|
||||
notas = fields.Text(string='Notas')
|
||||
|
||||
cita_ids = fields.Many2many('skeen.cita', string='Citas')
|
||||
|
||||
_sql_constraints = [
|
||||
('unique_code', 'unique(code)', 'El código del recurso debe ser único!')
|
||||
]
|
||||
|
||||
@api.model
|
||||
def _seleccion_activos(self):
|
||||
"""[(code, name)] de los recursos activos. Fallback a los valores de
|
||||
siempre cuando todavía no hay recursos (instancia sin migrar)."""
|
||||
recs = self.sudo().search([('activo', '=', True)], order='sequence, name')
|
||||
seleccion = [(r.code, r.name) for r in recs if r.code]
|
||||
return seleccion or [('consultoria', 'Consultoría'), ('cabina', 'Cabina')]
|
||||
Reference in New Issue
Block a user