Files
SKEEN-Proyecto/odoo-addons/skeen_monedero/models/monedero.py

162 lines
6.1 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class SkeenMonedero(models.Model):
_name = 'skeen.monedero'
_description = 'Monedero Digital de Fidelidad'
_order = 'create_date desc'
# Paciente
partner_id = fields.Many2one('res.partner', string='Paciente', required=True,
domain=[('is_patient', '=', True)])
partner_phone = fields.Char(related='partner_id.phone', string='Teléfono', readonly=True)
# Puntos
points = fields.Integer(string='Puntos', default=0)
equivalent_mxn = fields.Float(string='Equivalente MXN', compute='_compute_equivalent')
# Historial de transacciones
transaction_ids = fields.One2many('skeen.monedero.transaction', 'monedero_id', string='Transacciones')
# Estado
active = fields.Boolean(string='Activo', default=True)
@api.depends('points')
def _compute_equivalent(self):
for monedero in self:
monedero.equivalent_mxn = monedero.points * 1.0 # 1 punto = $1 MXN
def get_balance(self, phone):
"""Obtener saldo por teléfono (para API)"""
partner = self.env['res.partner'].search([('phone', '=', phone)], limit=1)
if not partner:
return {'points': 0, 'equivalent_mxn': 0, 'history': []}
monedero = self.search([('partner_id', '=', partner.id)], limit=1)
if not monedero:
return {'points': 0, 'equivalent_mxn': 0, 'history': []}
history = []
for tx in monedero.transaction_ids:
history.append({
'date': tx.create_date.strftime('%d/%m/%Y'),
'type': tx.type,
'points': tx.points,
'description': tx.description,
})
return {
'points': monedero.points,
'equivalent_mxn': monedero.equivalent_mxn,
'history': history,
}
def add_deposit(self, amount, description='', reference='', operator=''):
"""Recarga de saldo a favor (dinero a cuenta, p. ej. un anticipo).
A diferencia de add_points (puntos ganados por compra), el depósito es
dinero que el paciente paga por adelantado: suma al mismo saldo y se
puede canjear en el POS. El saldo se lleva en pesos enteros (1 pt = $1).
"""
self.ensure_one()
amount = int(round(float(amount or 0)))
if amount <= 0:
raise ValidationError(_('El monto de la recarga debe ser mayor a 0'))
self.write({'points': self.points + amount})
tx = self.env['skeen.monedero.transaction'].create({
'monedero_id': self.id,
'type': 'deposito',
'points': amount,
'description': description or 'Recarga de saldo a favor',
'reference': reference,
'operator': operator,
})
return tx
def add_points(self, points, description='', reference='', operator=''):
"""Agregar puntos al monedero"""
self.ensure_one()
self.write({'points': self.points + points})
self.env['skeen.monedero.transaction'].create({
'monedero_id': self.id,
'type': 'accrual',
'points': points,
'description': description or 'Acumulación de puntos',
'reference': reference,
'operator': operator,
})
return True
def redeem_points(self, points, description='', reference='', operator=''):
"""Redimir puntos del monedero"""
self.ensure_one()
if points > self.points:
raise ValidationError(_('No tiene suficientes puntos!'))
self.write({'points': self.points - points})
self.env['skeen.monedero.transaction'].create({
'monedero_id': self.id,
'type': 'redemption',
'points': -points,
'description': description or 'Redención de puntos',
'reference': reference,
'operator': operator,
})
return True
def adjust_points(self, delta, description='', reference='', operator=''):
"""Ajuste de puntos (puede ser negativo). Hace piso en 0 para no dejar saldo negativo.
Usado por devoluciones para revertir puntos acumulados por una venta.
Devuelve el delta efectivamente aplicado (puede ser menor si se pisó en 0).
"""
self.ensure_one()
delta = int(delta or 0)
new_points = self.points + delta
effective_delta = delta
if new_points < 0:
effective_delta = -self.points # solo revertir hasta 0
new_points = 0
self.write({'points': new_points})
self.env['skeen.monedero.transaction'].create({
'monedero_id': self.id,
'type': 'adjustment',
'points': effective_delta,
'description': description or 'Ajuste de puntos',
'reference': reference,
'operator': operator,
})
return effective_delta
class SkeenMonederoTransaction(models.Model):
_name = 'skeen.monedero.transaction'
_description = 'Transacción de Monedero'
_order = 'create_date desc'
monedero_id = fields.Many2one('skeen.monedero', string='Monedero', required=True, ondelete='cascade')
partner_id = fields.Many2one(related='monedero_id.partner_id', string='Paciente', readonly=True)
# Transacción
type = fields.Selection([
('deposito', 'Depósito (saldo a favor)'),
('accrual', 'Acumulación'),
('redemption', 'Redención'),
('adjustment', 'Ajuste'),
('reversion', 'Reversión'),
('expiration', 'Vencimiento'),
], string='Tipo', required=True)
points = fields.Integer(string='Puntos', required=True)
description = fields.Text(string='Descripción')
reference = fields.Char(string='Referencia')
# Usuario del frontend que capturó el movimiento (los controladores
# auth='none' no dejan uid de Odoo, así que se guarda explícito).
operator = fields.Char(string='Registrado por')
# Fecha
create_date = fields.Datetime(string='Fecha', readonly=True, default=fields.Datetime.now)