bloque 2: cuenta del cliente (modulo skeen_portal_cliente: acceso con codigo por WhatsApp o enlace por correo, sesion propia separada del personal, mis citas con cancelar y reagendar, pagos, monedero, paquetes, membresias con pago del periodo, formularios, documentos y perfil; invitacion y control de sesiones desde el expediente); apagado por defecto
This commit is contained in:
3
odoo-addons/skeen_portal_cliente/controllers/__init__.py
Normal file
3
odoo-addons/skeen_portal_cliente/controllers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import public_portal
|
||||
from . import staff_portal
|
||||
1225
odoo-addons/skeen_portal_cliente/controllers/public_portal.py
Normal file
1225
odoo-addons/skeen_portal_cliente/controllers/public_portal.py
Normal file
File diff suppressed because it is too large
Load Diff
181
odoo-addons/skeen_portal_cliente/controllers/staff_portal.py
Normal file
181
odoo-addons/skeen_portal_cliente/controllers/staff_portal.py
Normal file
@@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Portal del cliente: endpoints del PERSONAL (invitar, accesos, sesiones).
|
||||
|
||||
Bajo `/skeen/frontend/v1/portal`, autenticados con la sesión del personal
|
||||
(`require_perm`). Un token del portal del cliente NO sirve aquí (no lleva `uid`).
|
||||
|
||||
Permiso nuevo: `portal.invitar` (invitar y cerrar sesiones) y `portal.sesiones`
|
||||
(ver el listado de accesos). Por defecto: admin, gerencia y recepción.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from odoo import fields, http
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.skeen_whatsapp.controllers.auth import (
|
||||
_json, require_perm, require_role,
|
||||
)
|
||||
from odoo.addons.skeen_whatsapp.controllers import public_booking as _pb
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
PREFIX = '/skeen/frontend/v1/portal'
|
||||
|
||||
|
||||
def _body():
|
||||
try:
|
||||
return json.loads(request.httprequest.get_data(as_text=True) or '{}')
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
class SkeenPortalStaffController(http.Controller):
|
||||
"""Gestión del portal del cliente desde la interfaz del personal."""
|
||||
|
||||
def _svc(self):
|
||||
return request.env['skeen.portal.service'].sudo()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Invitar al portal (envía el código o el enlace)
|
||||
# ------------------------------------------------------------------
|
||||
@http.route(PREFIX + '/invitar', type='http', auth='none',
|
||||
methods=['POST', 'OPTIONS'], csrf=False)
|
||||
@require_role('recepcion')
|
||||
@require_perm('portal.invitar')
|
||||
def portal_invitar(self, **kw):
|
||||
data = _body()
|
||||
try:
|
||||
partner = request.env['res.partner'].sudo().browse(
|
||||
int(data.get('partner_id') or 0))
|
||||
if not partner.exists() or not partner.is_patient:
|
||||
return _json({'status': 'error', 'message': 'Paciente no encontrado'}, 404)
|
||||
svc = self._svc()
|
||||
cfg = svc.cfg()
|
||||
if not cfg.get('activo'):
|
||||
return _json({'status': 'error',
|
||||
'message': 'El portal del cliente está apagado. '
|
||||
'Actívalo en Configuración.'}, 403)
|
||||
canal = str(data.get('canal') or '').strip()
|
||||
if canal not in ('whatsapp', 'email'):
|
||||
canal = svc.canal_para(cfg, partner, partner.email or partner.phone or '')
|
||||
if not svc.destino_disponible(partner, canal):
|
||||
canal = 'whatsapp' if svc.destino_disponible(partner, 'whatsapp') else 'email'
|
||||
if not svc.destino_disponible(partner, canal):
|
||||
return _json({'status': 'error',
|
||||
'message': 'El paciente no tiene teléfono ni correo.'}, 400)
|
||||
usuario = getattr(request, 'frontend_user', None)
|
||||
acceso = svc.acceso_de(partner, crear=True, metodo=cfg.get('metodo'),
|
||||
invitado_por=usuario.login if usuario else '')
|
||||
acceso.write({'activo': True, 'invitado_at': fields.Datetime.now()})
|
||||
salida = {'status': 'success', 'ok': True, 'canal': canal,
|
||||
'modo_prueba': svc.modo_prueba(),
|
||||
'acceso': svc.estado_paciente(partner)}
|
||||
if canal == 'whatsapp':
|
||||
codigo = svc.enviar_codigo(partner, ip=_pb._client_ip())
|
||||
if svc.modo_prueba():
|
||||
salida['codigo_prueba'] = codigo
|
||||
else:
|
||||
url = svc.enviar_enlace(partner, ip=_pb._client_ip())
|
||||
if svc.modo_prueba():
|
||||
salida['enlace_prueba'] = url
|
||||
return _json(salida)
|
||||
except Exception as exc:
|
||||
request.env.cr.rollback()
|
||||
_logger.exception('Error invitando al portal: %s', exc)
|
||||
return _json({'status': 'error',
|
||||
'message': 'No se pudo invitar al portal.'}, 500)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Estado del acceso de un paciente (ficha de expediente)
|
||||
# ------------------------------------------------------------------
|
||||
@http.route(PREFIX + '/paciente/<int:partner_id>', type='http', auth='none',
|
||||
methods=['GET', 'OPTIONS'], csrf=False)
|
||||
@require_role('lectura')
|
||||
@require_perm('portal.invitar')
|
||||
def portal_paciente_estado(self, partner_id, **kw):
|
||||
try:
|
||||
partner = request.env['res.partner'].sudo().browse(partner_id)
|
||||
if not partner.exists() or not partner.is_patient:
|
||||
return _json({'status': 'error', 'message': 'Paciente no encontrado'}, 404)
|
||||
return _json({'status': 'success',
|
||||
'activo': self._svc().activo(),
|
||||
'estado': self._svc().estado_paciente(partner)})
|
||||
except Exception as exc:
|
||||
_logger.exception('Error consultando acceso del portal: %s', exc)
|
||||
return _json({'status': 'error', 'message': 'No se pudo consultar.'}, 500)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Listado de accesos activos
|
||||
# ------------------------------------------------------------------
|
||||
@http.route(PREFIX + '/accesos', type='http', auth='none',
|
||||
methods=['GET', 'OPTIONS'], csrf=False)
|
||||
@require_role('lectura')
|
||||
@require_perm('portal.sesiones')
|
||||
def portal_accesos(self, **kw):
|
||||
try:
|
||||
svc = self._svc()
|
||||
return _json({'status': 'success',
|
||||
'activo': svc.activo(),
|
||||
'accesos': svc.lista_accesos()})
|
||||
except Exception as exc:
|
||||
_logger.exception('Error listando accesos del portal: %s', exc)
|
||||
return _json({'status': 'error', 'message': 'No se pudo consultar.'}, 500)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Cerrar sesiones de un paciente
|
||||
# ------------------------------------------------------------------
|
||||
@http.route(PREFIX + '/sesiones/cerrar', type='http', auth='none',
|
||||
methods=['POST', 'OPTIONS'], csrf=False)
|
||||
@require_role('recepcion')
|
||||
@require_perm('portal.invitar')
|
||||
def portal_cerrar_sesiones(self, **kw):
|
||||
data = _body()
|
||||
try:
|
||||
partner = request.env['res.partner'].sudo().browse(
|
||||
int(data.get('partner_id') or 0))
|
||||
if not partner.exists() or not partner.is_patient:
|
||||
return _json({'status': 'error', 'message': 'Paciente no encontrado'}, 404)
|
||||
svc = self._svc()
|
||||
acceso = svc.acceso_de(partner, crear=False)
|
||||
if not acceso:
|
||||
return _json({'status': 'error',
|
||||
'message': 'El paciente no tiene acceso al portal.'}, 404)
|
||||
acceso.action_cerrar_sesiones()
|
||||
return _json({'status': 'success', 'ok': True,
|
||||
'acceso': svc.estado_paciente(partner)})
|
||||
except Exception as exc:
|
||||
request.env.cr.rollback()
|
||||
_logger.exception('Error cerrando sesiones del portal: %s', exc)
|
||||
return _json({'status': 'error', 'message': 'No se pudo cerrar sesiones.'}, 500)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Activar / desactivar el acceso de un paciente
|
||||
# ------------------------------------------------------------------
|
||||
@http.route(PREFIX + '/acceso/<int:partner_id>/<string:accion>', type='http',
|
||||
auth='none', methods=['POST', 'OPTIONS'], csrf=False)
|
||||
@require_role('recepcion')
|
||||
@require_perm('portal.invitar')
|
||||
def portal_acceso_estado(self, partner_id, accion, **kw):
|
||||
try:
|
||||
partner = request.env['res.partner'].sudo().browse(partner_id)
|
||||
if not partner.exists() or not partner.is_patient:
|
||||
return _json({'status': 'error', 'message': 'Paciente no encontrado'}, 404)
|
||||
if accion not in ('activar', 'desactivar'):
|
||||
return _json({'status': 'error', 'message': 'Acción no válida'}, 400)
|
||||
svc = self._svc()
|
||||
acceso = svc.acceso_de(partner, crear=(accion == 'activar'))
|
||||
if not acceso:
|
||||
return _json({'status': 'error',
|
||||
'message': 'El paciente no tiene acceso al portal.'}, 404)
|
||||
activo = accion == 'activar'
|
||||
acceso.write({'activo': activo})
|
||||
if not activo:
|
||||
acceso.action_cerrar_sesiones()
|
||||
return _json({'status': 'success', 'ok': True,
|
||||
'acceso': svc.estado_paciente(partner)})
|
||||
except Exception as exc:
|
||||
request.env.cr.rollback()
|
||||
_logger.exception('Error cambiando el acceso al portal: %s', exc)
|
||||
return _json({'status': 'error', 'message': 'No se pudo actualizar.'}, 500)
|
||||
Reference in New Issue
Block a user