bloque 3: lealtad configurable (motor de puntos con multiplicadores por servicio/categoria/sucursal/dia/nivel, niveles VIP con descuento y factor, expiracion, ajuste manual con motivo y reportes) + propinas en punto de venta con reparto entre el personal, desglose en ticket y corte, y opcion en la liquidacion de comisiones; modo clasico y propinas apagadas preservan el comportamiento actual

This commit is contained in:
2026-10-12 01:37:07 +00:00
parent 1bd4cad6a0
commit 705b5a2842
28 changed files with 2748 additions and 59 deletions

View File

@@ -174,6 +174,7 @@ class SkeenComisionesController(http.Controller):
'periodo_fin': l.periodo_fin.strftime('%Y-%m-%d') if l.periodo_fin else None,
'periodo': l.periodo or '',
'total_calculado': l.total_calculado,
'total_propinas': l.total_propinas,
'total_ajustes': l.total_ajustes,
'total': l.total,
'estado': l.estado,
@@ -596,9 +597,12 @@ class SkeenComisionesController(http.Controller):
emp_ids = [int(data['empleado_id'])]
calc = motor.calcular(start, end, empleado_ids=emp_ids)
from odoo.addons.skeen_comisiones.models.liquidacion import propinas_de_empleado
creadas, omitidas = [], []
for emp in calc['empleados']:
if emp['lineas_count'] == 0 and abs(emp['total']) < 1e-9:
propina = propinas_de_empleado(request.env, emp['empleado_id'], start, end)
if emp['lineas_count'] == 0 and abs(emp['total']) < 1e-9 and propina <= 0:
continue
existente = Liq.search([
('empleado_id', '=', emp['empleado_id']),
@@ -610,12 +614,15 @@ class SkeenComisionesController(http.Controller):
'folio': existente.name,
'motivo': 'ya existe liquidación del periodo'})
continue
detalle = dict(emp)
detalle['propinas'] = propina
liq = Liq.create({
'empleado_id': emp['empleado_id'],
'periodo_inicio': start,
'periodo_fin': end,
'total_calculado': emp['total'],
'detalle': json.dumps(emp, ensure_ascii=False),
'total_propinas': propina,
'detalle': json.dumps(detalle, ensure_ascii=False),
'creado_por_login': _login(),
'notas': (data.get('notas') or '').strip(),
})

View File

@@ -15,10 +15,29 @@ import json
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.addons.skeen_citas.clinic_settings import get_propinas
ESTADOS = ('borrador', 'pagada', 'cancelada')
ESTADO_LABEL = {'borrador': 'Borrador', 'pagada': 'Pagada', 'cancelada': 'Cancelada'}
def propinas_de_empleado(env, empleado_id, start, end):
"""Propina que le toca a un empleado en el periodo (0 si no aplica).
Solo se suma a la liquidación cuando la configuración de propinas lo pide
(`incluir_en_liquidacion_comisiones`); apagado, devuelve 0 y no altera
ninguna liquidación.
"""
cfg = get_propinas(env)
if not cfg.get('activo') or not cfg.get('incluir_en_liquidacion_comisiones'):
return 0.0
repartos = env['skeen.propina.reparto'].sudo().search([
('employee_id', '=', empleado_id),
('date', '>=', start), ('date', '<=', end),
])
return sum(r.monto or 0.0 for r in repartos)
class SkeenComisionLiquidacion(models.Model):
_name = 'skeen.comision.liquidacion'
_description = 'Liquidación de comisiones SKEEN'
@@ -33,6 +52,10 @@ class SkeenComisionLiquidacion(models.Model):
store=True, index=True)
total_calculado = fields.Float(string='Comisión calculada', default=0.0)
# Propina del empleado en el periodo. Solo tiene valor con
# `propinas.incluir_en_liquidacion_comisiones = true`; en cualquier otro
# caso queda en 0 y no cambia la liquidación.
total_propinas = fields.Float(string='Propinas', default=0.0)
total_ajustes = fields.Float(string='Ajustes', compute='_compute_total',
store=True)
total = fields.Float(string='Total a pagar', compute='_compute_total', store=True)
@@ -62,11 +85,11 @@ class SkeenComisionLiquidacion(models.Model):
for l in self:
l.periodo = l.periodo_inicio.strftime('%Y-%m') if l.periodo_inicio else ''
@api.depends('ajuste_ids.monto', 'total_calculado')
@api.depends('ajuste_ids.monto', 'total_calculado', 'total_propinas')
def _compute_total(self):
for l in self:
l.total_ajustes = sum(a.monto for a in l.ajuste_ids)
l.total = (l.total_calculado or 0.0) + l.total_ajustes
l.total = (l.total_calculado or 0.0) + l.total_ajustes + (l.total_propinas or 0.0)
@api.model_create_multi
def create(self, vals_list):