Files
Odoo-18.0-20251222/sale_fixed_discount/models/sale_order_line.py
tocmo0nlord adbe430761
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled
Initial commit: Odoo 18.0-20251222 extra-addons
2026-03-13 20:43:25 +00:00

105 lines
3.9 KiB
Python
Executable File

# Copyright 2017-20 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare, float_round
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
discount_fixed = fields.Float(
string="Discount (Fixed)",
digits="Product Price",
help="Fixed amount discount.",
)
@api.constrains("discount_fixed", "discount")
def _check_discounts(self):
"""Check that the fixed discount and the discount percentage are consistent."""
for line in self:
if line.discount_fixed and line.discount:
currency = line.currency_id
calculated_fixed_discount = float_round(
line._get_discount_from_fixed_discount(),
precision_rounding=currency.rounding,
)
if (
float_compare(
calculated_fixed_discount,
line.discount,
precision_rounding=currency.rounding,
)
!= 0
):
raise ValidationError(
self.env._(
"The fixed discount %(fixed)s does not match the calculated"
"discount %(discount)s %%."
"Please correct one of the discounts.",
fixed=line.discount_fixed,
discount=line.discount,
)
)
def _prepare_base_line_for_taxes_computation(self, **kwargs):
"""Prior to calculating the tax toals for a line, update the discount value
used in the tax calculation to the full float value. Otherwise, we get rounding
errors in the resulting calculated totals.
For example:
- price_unit = 750.0
- discount_fixed = 100.0
- discount = 13.33
=> price_subtotal = 650.03
:return: A python dictionary.
"""
self.ensure_one()
# Accurately pass along the fixed discount amount to the tax computation method.
if self.discount_fixed:
return self.env["account.tax"]._prepare_base_line_for_taxes_computation(
self,
**{
"tax_ids": self.tax_id,
"quantity": self.product_uom_qty,
"partner_id": self.order_id.partner_id,
"currency_id": self.order_id.currency_id
or self.order_id.company_id.currency_id,
"rate": self.order_id.currency_rate,
"discount": self._get_discount_from_fixed_discount(),
**kwargs,
},
)
return super()._prepare_base_line_for_taxes_computation(**kwargs)
@api.depends("discount_fixed", "price_unit")
def _compute_discount(self):
lines_with_discount_fixed = self.filtered(lambda sol: sol.discount_fixed)
for line in lines_with_discount_fixed:
line.discount = line._get_discount_from_fixed_discount()
return super(
SaleOrderLine, self - lines_with_discount_fixed
)._compute_discount()
def _get_discount_from_fixed_discount(self):
"""Calculate the discount percentage from the fixed discount amount."""
self.ensure_one()
if not self.discount_fixed:
return 0.0
return (
(self.price_unit != 0)
and ((self.discount_fixed) / self.price_unit) * 100
or 0.00
)
def _prepare_invoice_line(self, **optional_values):
res = super()._prepare_invoice_line(**optional_values)
res.update({"discount_fixed": self.discount_fixed})
return res