mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
363 lines
14 KiB
Python
363 lines
14 KiB
Python
# Copyright 2023 Domatix - Carlos Martínez
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
from odoo import _, api, fields, models
|
|
from odoo.tools.misc import get_lang
|
|
|
|
|
|
class SaleSubscriptionLine(models.Model):
|
|
_name = "sale.subscription.line"
|
|
_description = "Subscription lines added to a given subscription"
|
|
|
|
product_id = fields.Many2one(
|
|
comodel_name="product.product",
|
|
domain=[("sale_ok", "=", True)],
|
|
string="Product",
|
|
)
|
|
currency_id = fields.Many2one(
|
|
"res.currency",
|
|
related="sale_subscription_id.currency_id",
|
|
store=True,
|
|
readonly=True,
|
|
)
|
|
name = fields.Char(
|
|
string="Description", compute="_compute_name", store=True, readonly=False
|
|
)
|
|
product_uom_qty = fields.Float(default=1.0, string="Quantity")
|
|
price_unit = fields.Float(
|
|
string="Unit price", compute="_compute_price_unit", store=True, readonly=False
|
|
)
|
|
discount = fields.Float(
|
|
string="Discount (%)", compute="_compute_discount", store=True, readonly=False
|
|
)
|
|
tax_ids = fields.Many2many(
|
|
comodel_name="account.tax",
|
|
relation="subscription_line_tax",
|
|
column1="subscription_line_id",
|
|
column2="tax_id",
|
|
string="Taxes",
|
|
compute="_compute_tax_ids",
|
|
store=True,
|
|
readonly=False,
|
|
)
|
|
|
|
@api.depends("product_id", "price_unit", "product_uom_qty", "discount", "tax_ids")
|
|
def _compute_subtotal(self):
|
|
for record in self:
|
|
price = record.price_unit * (1 - (record.discount or 0.0) / 100.0)
|
|
taxes = record.tax_ids.compute_all(
|
|
price,
|
|
record.currency_id,
|
|
record.product_uom_qty,
|
|
product=record.product_id,
|
|
partner=record.sale_subscription_id.partner_id,
|
|
)
|
|
record.update(
|
|
{
|
|
"amount_tax_line_amount": sum(
|
|
t.get("amount", 0.0) for t in taxes.get("taxes", [])
|
|
),
|
|
"price_total": taxes["total_included"],
|
|
"price_subtotal": taxes["total_excluded"],
|
|
}
|
|
)
|
|
|
|
price_subtotal = fields.Monetary(
|
|
string="Subtotal", readonly="True", compute=_compute_subtotal, store=True
|
|
)
|
|
price_total = fields.Monetary(
|
|
string="Total", readonly="True", compute=_compute_subtotal, store=True
|
|
)
|
|
amount_tax_line_amount = fields.Float(
|
|
string="Taxes Amount", compute="_compute_subtotal", store=True
|
|
)
|
|
sale_subscription_id = fields.Many2one(
|
|
comodel_name="sale.subscription", string="Subscription"
|
|
)
|
|
company_id = fields.Many2one(
|
|
related="sale_subscription_id.company_id",
|
|
string="Company",
|
|
store=True,
|
|
index=True,
|
|
)
|
|
|
|
@api.depends("product_id")
|
|
def _compute_name(self):
|
|
for record in self:
|
|
if not record.product_id:
|
|
record.name = False
|
|
lang = get_lang(self.env, record.sale_subscription_id.partner_id.lang).code
|
|
product = record.product_id.with_context(lang=lang)
|
|
record.name = product.with_context(
|
|
lang=lang
|
|
).get_product_multiline_description_sale()
|
|
|
|
@api.depends("product_id", "sale_subscription_id.fiscal_position_id")
|
|
def _compute_tax_ids(self):
|
|
for line in self:
|
|
fpos = (
|
|
line.sale_subscription_id.fiscal_position_id
|
|
or line.sale_subscription_id.fiscal_position_id.get_fiscal_position(
|
|
line.sale_subscription_id.partner_id.id
|
|
)
|
|
)
|
|
# If company_id is set, always filter taxes by the company
|
|
taxes = line.product_id.taxes_id.filtered(
|
|
lambda t: t.company_id == line.env.company
|
|
)
|
|
line.tax_ids = fpos.map_tax(taxes)
|
|
|
|
@api.depends(
|
|
"product_id",
|
|
"sale_subscription_id.partner_id",
|
|
"sale_subscription_id.pricelist_id",
|
|
)
|
|
def _compute_price_unit(self):
|
|
for record in self:
|
|
if not record.product_id:
|
|
continue
|
|
if (
|
|
record.sale_subscription_id.pricelist_id
|
|
and record.sale_subscription_id.partner_id
|
|
):
|
|
product = record.product_id.with_context(
|
|
partner=record.sale_subscription_id.partner_id,
|
|
quantity=record.product_uom_qty,
|
|
date=fields.datetime.now(),
|
|
pricelist=record.sale_subscription_id.pricelist_id.id,
|
|
uom=record.product_id.uom_id.id,
|
|
)
|
|
record.price_unit = product._get_tax_included_unit_price(
|
|
record.company_id,
|
|
record.sale_subscription_id.currency_id,
|
|
fields.datetime.now(),
|
|
"sale",
|
|
fiscal_position=record.sale_subscription_id.fiscal_position_id,
|
|
product_price_unit=record._get_display_price(product),
|
|
product_currency=record.sale_subscription_id.currency_id,
|
|
)
|
|
|
|
@api.depends(
|
|
"product_id",
|
|
"price_unit",
|
|
"product_uom_qty",
|
|
"tax_ids",
|
|
"sale_subscription_id.partner_id",
|
|
"sale_subscription_id.pricelist_id",
|
|
)
|
|
def _compute_discount(self):
|
|
for record in self:
|
|
if not (
|
|
record.product_id
|
|
and record.product_id.uom_id
|
|
and record.sale_subscription_id.partner_id
|
|
and record.sale_subscription_id.pricelist_id
|
|
and record.sale_subscription_id.pricelist_id.discount_policy
|
|
== "without_discount"
|
|
and self.env.user.has_group("product.group_discount_per_so_line")
|
|
):
|
|
record.discount = 0.0
|
|
continue
|
|
|
|
record.discount = 0.0
|
|
product = record.product_id.with_context(
|
|
lang=record.sale_subscription_id.partner_id.lang,
|
|
partner=record.sale_subscription_id.partner_id,
|
|
quantity=record.product_uom_qty,
|
|
date=fields.Datetime.now(),
|
|
pricelist=record.sale_subscription_id.pricelist_id.id,
|
|
uom=record.product_id.uom_id.id,
|
|
fiscal_position=record.sale_subscription_id.fiscal_position_id
|
|
or self.env.context.get("fiscal_position"),
|
|
)
|
|
|
|
price, rule_id = record.sale_subscription_id.pricelist_id.with_context(
|
|
partner_id=record.sale_subscription_id.partner_id.id,
|
|
date=fields.Datetime.now(),
|
|
uom=record.product_id.uom_id.id,
|
|
).get_product_price_rule(
|
|
record.product_id,
|
|
record.product_uom_qty or 1.0,
|
|
record.sale_subscription_id.partner_id,
|
|
)
|
|
new_list_price, currency = record.with_context(
|
|
partner_id=record.sale_subscription_id.partner_id.id,
|
|
date=fields.Datetime.now(),
|
|
uom=record.product_id.uom_id.id,
|
|
)._get_real_price_currency(
|
|
product, rule_id, record.product_uom_qty, record.product_id.uom_id
|
|
)
|
|
|
|
if new_list_price != 0:
|
|
if record.sale_subscription_id.pricelist_id.currency_id != currency:
|
|
new_list_price = currency._convert(
|
|
new_list_price,
|
|
record.sale_subscription_id.pricelist_id.currency_id,
|
|
record.sale_subscription_id.company_id or self.env.company,
|
|
fields.Date.today(),
|
|
)
|
|
discount = (new_list_price - price) / new_list_price * 100
|
|
if (discount > 0 and new_list_price > 0) or (
|
|
discount < 0 and new_list_price < 0
|
|
):
|
|
record.discount = discount
|
|
|
|
def _get_real_price_currency(self, product, rule_id, qty, uom):
|
|
PricelistItem = self.env["product.pricelist.item"]
|
|
field_name = "lst_price"
|
|
currency_id = None
|
|
product_currency = product.currency_id
|
|
if rule_id:
|
|
pricelist_item = PricelistItem.browse(rule_id)
|
|
if pricelist_item.pricelist_id.discount_policy == "without_discount":
|
|
while (
|
|
pricelist_item.base == "pricelist"
|
|
and pricelist_item.base_pricelist_id
|
|
and pricelist_item.base_pricelist_id.discount_policy
|
|
== "without_discount"
|
|
):
|
|
_price, rule_id = pricelist_item.base_pricelist_id.with_context(
|
|
uom=uom.id
|
|
).get_product_price_rule(
|
|
product, qty, self.sale_subscription_id.partner_id
|
|
)
|
|
pricelist_item = PricelistItem.browse(rule_id)
|
|
|
|
if pricelist_item.base == "standard_price":
|
|
field_name = "standard_price"
|
|
product_currency = product.cost_currency_id
|
|
elif (
|
|
pricelist_item.base == "pricelist" and pricelist_item.base_pricelist_id
|
|
):
|
|
field_name = "price"
|
|
product = product.with_context(
|
|
pricelist=pricelist_item.base_pricelist_id.id
|
|
)
|
|
product_currency = pricelist_item.base_pricelist_id.currency_id
|
|
currency_id = pricelist_item.pricelist_id.currency_id
|
|
|
|
if not currency_id:
|
|
currency_id = product_currency
|
|
cur_factor = 1.0
|
|
else:
|
|
if currency_id.id == product_currency.id:
|
|
cur_factor = 1.0
|
|
else:
|
|
cur_factor = currency_id._get_conversion_rate(
|
|
product_currency,
|
|
currency_id,
|
|
self.company_id or self.env.company,
|
|
fields.Date.today(),
|
|
)
|
|
|
|
product_uom = self.env.context.get("uom") or product.uom_id.id
|
|
if uom and uom.id != product_uom:
|
|
# the unit price is in a different uom
|
|
uom_factor = uom._compute_price(1.0, product.uom_id)
|
|
else:
|
|
uom_factor = 1.0
|
|
|
|
return product[field_name] * uom_factor * cur_factor, currency_id
|
|
|
|
def _get_display_price(self, product):
|
|
if self.sale_subscription_id.pricelist_id.discount_policy == "with_discount":
|
|
return product.with_context(
|
|
pricelist=self.sale_subscription_id.pricelist_id.id,
|
|
uom=self.product_id.uom_id.id,
|
|
).price
|
|
|
|
final_price, rule_id = self.sale_subscription_id.pricelist_id.with_context(
|
|
partner_id=self.sale_subscription_id.partner_id.id,
|
|
date=fields.Datetime.now(),
|
|
uom=self.product_id.uom_id.id,
|
|
).get_product_price_rule(
|
|
product or self.product_id,
|
|
self.product_uom_qty or 1.0,
|
|
self.sale_subscription_id.partner_id,
|
|
)
|
|
base_price, currency = self.with_context(
|
|
partner_id=self.sale_subscription_id.partner_id.id,
|
|
date=fields.Datetime.now(),
|
|
uom=self.product_id.uom_id.id,
|
|
)._get_real_price_currency(
|
|
product, rule_id, self.product_uom_qty, self.product_id.uom_id
|
|
)
|
|
if currency != self.sale_subscription_id.pricelist_id.currency_id:
|
|
base_price = currency._convert(
|
|
base_price,
|
|
self.sale_subscription_id.pricelist_id.currency_id,
|
|
self.sale_subscription_id.company_id or self.env.company,
|
|
fields.Date.today(),
|
|
)
|
|
return max(base_price, final_price)
|
|
|
|
def _prepare_sale_order_line(self, start_date, end_date):
|
|
self.ensure_one()
|
|
return {
|
|
"product_id": self.product_id.id,
|
|
"name": self._generate_name(start_date, end_date),
|
|
"product_uom_qty": self.product_uom_qty,
|
|
"price_unit": self.price_unit,
|
|
"discount": self.discount,
|
|
"price_subtotal": self.price_subtotal,
|
|
"tax_id": self.tax_ids,
|
|
"product_uom": self.product_id.uom_id.id,
|
|
}
|
|
|
|
def _prepare_account_move_line(self, start_date, end_date):
|
|
self.ensure_one()
|
|
account = (
|
|
self.product_id.property_account_income_id
|
|
or self.product_id.categ_id.property_account_income_categ_id
|
|
)
|
|
return {
|
|
"product_id": self.product_id.id,
|
|
"name": self._generate_name(start_date, end_date),
|
|
"quantity": self.product_uom_qty,
|
|
"price_unit": self.price_unit,
|
|
"discount": self.discount,
|
|
"price_subtotal": self.price_subtotal,
|
|
"tax_ids": [(6, 0, self.tax_ids.ids)],
|
|
"product_uom_id": self.product_id.uom_id.id,
|
|
"account_id": account.id,
|
|
}
|
|
|
|
def _generate_name(self, start_date, end_date):
|
|
return self._insert_markers(start_date, end_date)
|
|
|
|
def _insert_markers(self, start_date, end_date):
|
|
self.ensure_one()
|
|
lang_obj = self.env["res.lang"]
|
|
lang = lang_obj.search(
|
|
[("code", "=", self.sale_subscription_id.partner_id.lang)]
|
|
)
|
|
date_format = lang.date_format or "%m/%d/%Y"
|
|
name = self.name
|
|
name = name.replace("#START#", start_date.strftime(date_format))
|
|
name = name.replace("#END#", end_date.strftime(date_format)) if end_date else ""
|
|
name = name.replace("#INVOICEMONTHNUMBER#", start_date.strftime("%m"))
|
|
name = name.replace("#INVOICEYEAR#", start_date.strftime("%Y"))
|
|
name = name.replace(
|
|
"#INVOICEMONTHNAME#",
|
|
self.with_context(lang=lang.code)._translate_marker_month_name(
|
|
start_date.strftime("%m")
|
|
),
|
|
)
|
|
return name
|
|
|
|
def _translate_marker_month_name(self, month_name):
|
|
months = {
|
|
"01": _("January"),
|
|
"02": _("February"),
|
|
"03": _("March"),
|
|
"04": _("April"),
|
|
"05": _("May"),
|
|
"06": _("June"),
|
|
"07": _("July"),
|
|
"08": _("August"),
|
|
"09": _("September"),
|
|
"10": _("October"),
|
|
"11": _("November"),
|
|
"12": _("December"),
|
|
}
|
|
return months[month_name]
|