Agregando descuentos en las órdenes de compra

3 de noviembre de 2023 por
Gustavo Orrillo
| Sin comentarios aún
 

Para mi sorpresa me encontré que los descuentos en las líneas de las órdenes de compra desaparecieron en el core de Odoo Community. Cuando sucedió? La verdad no lo se, pero lo bueno es que OCA agrego dicha funcionalidad (y más) al repositorio purchase-workflow.

Una vez instalado el módulo purchase_discount, podemos apreciar cómo se agrega el descuento otra vez a la línea de la orden de compra


Pero no solo eso (y esto es lo interesante). Podemos agregar en el formulario del proveedor un descuento por defecto


Y tambien se puede definir en la lista de precios del proveedor el descuento que se recibe por producto.


Bastante completo, mucho más de lo que se ofrecía en el core de Odoo

Notas técnicas


Si revisan el código verán que el mismo hace muchas cosas interesantes, por ejemplo agregar la información del descuento a las listas de precio. Pero vamos a concentrarnos en explicar como extiende las consultas de compras y como calcula los valores de los pedidos de compra

Cómo extender las consultas de Odoo

Odoo brinda unas consultas tipo pivot (se pueden ver como listas pero son poco usables) muy populares. Dichas consultas permiten analizar la facturación, las ventas y las compras. Como se extienden dichas consultas? El módulo purchase_discount muestra como, agregando la columna discount a las consultas

class PurchaseReport(models.Model):
_inherit = "purchase.report"

discount = fields.Float(
string="Discount (%)", digits="Discount", group_operator="avg"
)

def _select(self):
res = super()._select()
# There are 3 matches
res = res.replace("l.price_unit", self._get_discounted_price_unit_exp())
res += ", l.discount AS discount"
return res

def _group_by(self):
res = super()._group_by()
res += ", l.discount"
return res

def _get_discounted_price_unit_exp(self):
"""Inheritable method for getting the SQL expression used for
calculating the unit price with discount(s).

:rtype: str
:return: SQL expression for discounted unit price.
"""
return "(1.0 - COALESCE(l.discount, 0.0) / 100.0) * l.price_unit"

Como pueden ver se define un campo nuevo en el reporte, llamado discount. Y luego se extendienden los métodos que construyen la senttencia del select, group by, y el calculo del descuento.

Agregando el descuento al cálculo de los valores de los pedidos de compra

Por una parte agrega el descuento al depends que calcula el valor de la compra

# adding discount to depends
@api.depends("discount")
def _compute_amount(self):
return super()._compute_amount()

Lo que hace que el valor de la compra se recalcule cada vez que se cambie el monto, cantidad y también descuento. Luego se modifica el método que calcula todos los valores, cambiando el cálculo del precio unitario para que incluya el descuento


def _prepare_compute_all_values(self):
vals = super()._prepare_compute_all_values()
vals.update({"price_unit": self._get_discounted_price_unit()})
return vals


 Es interesante como implementa el constraint del campo discount, hace que sea mediante SQL. No soporta valores negativos, lo que tiene el efecto colateral que un descuento negativo pasaría a ser un recargo (hay un caso de uso que se me viene a la cabeza para ello)


_sql_constraints = [
(
"discount_limit",
"CHECK (discount <= 100.0)",
"Discount must be lower than 100%.",
)
]

Por último, el método que retorna el precio unitario recalculado si el mismo incluye descuentos.


def _get_discounted_price_unit(self):
"""Inheritable method for getting the unit price after applying
discount(s).

:rtype: float
:return: Unit price after discount(s).
"""
self.ensure_one()
if self.discount:
return self.price_unit * (1 - self.discount / 100)
return self.price_unit
Gustavo Orrillo 3 de noviembre de 2023
Compartir
Categorías
Archivar
Identificarse dejar un comentario