fase 3.3: comisiones por reglas y liquidacion (modulo skeen_comisiones: motor con reglas por servicio/categoria/articulo/membresia/paquete, monto fijo y escalonado por metas, base vendido/cobrado con y sin impuestos, neto de devoluciones, metas con bonos, ajustes y liquidacion por periodo); reporte legacy intacto con el motor apagado
This commit is contained in:
59
odoo-addons/skeen_comisiones/models/meta.py
Normal file
59
odoo-addons/skeen_comisiones/models/meta.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Metas de comisión por empleado y periodo.
|
||||
|
||||
Una meta compara la venta (base comisionable del periodo, según la base
|
||||
configurada) del empleado contra `monto_objetivo`. Al alcanzarla se paga el
|
||||
bono: `fijo` (monto en m.n.) o `porcentaje` (sobre la base del empleado). Se
|
||||
evalúa al cerrar el periodo (al generar la liquidación) y también en vivo.
|
||||
|
||||
`periodo` acepta 'AAAA-MM' (mes concreto) o 'mensual' (cualquier mes). Se
|
||||
documenta así para no ambigüedad: una meta 'mensual' aplica a todo periodo
|
||||
consultado; una meta 'AAAA-MM' solo al mes que coincide con el inicio del rango.
|
||||
"""
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
TIPOS_BONO = ('fijo', 'porcentaje')
|
||||
|
||||
|
||||
class SkeenComisionMeta(models.Model):
|
||||
_name = 'skeen.comision.meta'
|
||||
_description = 'Meta de comisión SKEEN'
|
||||
_order = 'empleado_id, periodo'
|
||||
|
||||
empleado_id = fields.Many2one('hr.employee', string='Empleado', required=True,
|
||||
ondelete='cascade', index=True)
|
||||
periodo = fields.Char(string='Periodo', required=True,
|
||||
help="'AAAA-MM' para un mes concreto o 'mensual' para cualquiera.")
|
||||
monto_objetivo = fields.Float(string='Monto objetivo', default=0.0)
|
||||
bono = fields.Float(string='Bono', default=0.0)
|
||||
tipo_bono = fields.Selection(
|
||||
[('fijo', 'Monto fijo'), ('porcentaje', 'Porcentaje sobre la venta')],
|
||||
string='Tipo de bono', default='fijo', required=True)
|
||||
activo = fields.Boolean(string='Activa', default=True)
|
||||
notas = fields.Text(string='Notas')
|
||||
company_id = fields.Many2one('res.company', string='Compañía',
|
||||
default=lambda self: self.env.company)
|
||||
|
||||
@api.constrains('periodo')
|
||||
def _check_periodo(self):
|
||||
for m in self:
|
||||
p = (m.periodo or '').strip()
|
||||
if p == 'mensual':
|
||||
continue
|
||||
try:
|
||||
anio, mes = p.split('-')
|
||||
int(anio)
|
||||
mes_i = int(mes)
|
||||
if not (1 <= mes_i <= 12) or len(mes) != 2:
|
||||
raise ValueError
|
||||
except (ValueError, AttributeError):
|
||||
raise ValidationError(
|
||||
"El periodo debe ser 'AAAA-MM' (p. ej. 2026-10) o 'mensual'.")
|
||||
|
||||
def aplica_a(self, periodo_mes):
|
||||
"""True si la meta cubre el mes 'AAAA-MM' dado."""
|
||||
self.ensure_one()
|
||||
p = (self.periodo or '').strip()
|
||||
return p == 'mensual' or p == periodo_mes
|
||||
Reference in New Issue
Block a user