# -*- coding: utf-8 -*- """Aplicación de los límites de la licencia. Solo actúan con `modo='bloqueo'` y un límite > 0. Con `aviso` (default) o sin licencia no bloquean nada. Nunca afectan tareas internas: se pueden saltar con el contexto `skeen_licencia_skip=True` (cron, migraciones, importaciones). """ import logging from datetime import date from odoo import _, api, fields, models from odoo.exceptions import UserError from odoo.addons.skeen_citas.clinic_settings import ( licencia_de, limite_licencia, licencia_bloqueo_activo, ) _logger = logging.getLogger(__name__) MENSAJES = { 'usuarios_max': 'usuarios', 'sucursales_max': 'sucursales', 'citas_mes_max': 'citas este mes', 'almacenamiento_mb': 'MB de almacenamiento', } def _skip(env): return bool(env.context.get('skeen_licencia_skip') or env.context.get('install_mode')) def exigir_limite(env, clave, etiqueta, actual, agregando=1): """Lanza UserError si `actual + agregando` supera el límite de `clave`. Con modo=aviso solo deja una advertencia en el log. Devuelve False si no aplica (sin licencia, sin límite o contexto de salto). """ limite = limite_licencia(env, clave) if limite <= 0 or _skip(env): return False licencia = licencia_de(env) if not licencia_bloqueo_activo(licencia): if actual + agregando > limite: _logger.info('SKEEN licencia (aviso): %s excede el límite de %s ' '(%s + %s > %s)', etiqueta, limite, actual, agregando, limite) return False if actual + agregando > limite: raise UserError(_( 'Tu plan permite hasta %(limite)s %(etiqueta)s y ya tienes ' '%(actual)s. Para ampliar el límite, contacta a tu proveedor y ' 'solicita una licencia con un tope mayor.' ) % {'limite': limite, 'etiqueta': etiqueta, 'actual': actual}) return True def _contar_usuarios(env): return env['skeen.frontend.user'].sudo().search_count([('active', '=', True)]) def _contar_sucursales(env): return env['skeen.sucursal'].sudo().search_count([('active', '=', True)]) def _contar_citas_mes(env): hoy = date.today() inicio = hoy.replace(day=1) if hoy.month == 12: fin = hoy.replace(year=hoy.year + 1, month=1, day=1) else: fin = hoy.replace(month=hoy.month + 1, day=1) return env['skeen.cita'].sudo().search_count([ ('date', '>=', inicio), ('date', '<', fin), ]) def _mb_almacenamiento(env): env.cr.execute('SELECT COALESCE(SUM(file_size), 0) FROM ir_attachment') total = env.cr.fetchone()[0] or 0 return total / (1024.0 * 1024.0) class SkeenFrontendUser(models.Model): _inherit = 'skeen.frontend.user' @api.model_create_multi def create(self, vals_list): exigir_limite(self.env, 'usuarios_max', MENSAJES['usuarios_max'], _contar_usuarios(self.env), len(vals_list)) return super().create(vals_list) class SkeenSucursal(models.Model): _inherit = 'skeen.sucursal' @api.model_create_multi def create(self, vals_list): exigir_limite(self.env, 'sucursales_max', MENSAJES['sucursales_max'], _contar_sucursales(self.env), len(vals_list)) return super().create(vals_list) class SkeenCita(models.Model): _inherit = 'skeen.cita' @api.model_create_multi def create(self, vals_list): exigir_limite(self.env, 'citas_mes_max', MENSAJES['citas_mes_max'], _contar_citas_mes(self.env), len(vals_list)) return super().create(vals_list) class IrAttachment(models.Model): _inherit = 'ir.attachment' @api.model_create_multi def create(self, vals_list): if limite_licencia(self.env, 'almacenamiento_mb') > 0 and not _skip(self.env): nuevos_mb = sum(max(0, int(v.get('file_size') or 0)) for v in vals_list) \ / (1024.0 * 1024.0) exigir_limite(self.env, 'almacenamiento_mb', MENSAJES['almacenamiento_mb'], _mb_almacenamiento(self.env), nuevos_mb) return super().create(vals_list)