mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP] subscription_oca: enable markers to print invoice names
(like in _contract_)
This commit is contained in:
@@ -277,6 +277,7 @@ class SaleSubscription(models.Model):
|
||||
return values
|
||||
|
||||
def create_invoice(self):
|
||||
self.ensure_one()
|
||||
if not self.env["account.move"].check_access_rights("create", False):
|
||||
try:
|
||||
self.check_access_rights("write")
|
||||
@@ -284,8 +285,10 @@ class SaleSubscription(models.Model):
|
||||
except AccessError:
|
||||
return self.env["account.move"]
|
||||
line_ids = []
|
||||
start_date = self.recurring_next_date or self.date_start
|
||||
end_date = self._get_next_period_date_end(start_date, self.date)
|
||||
for line in self.sale_subscription_line_ids:
|
||||
line_values = line._prepare_account_move_line()
|
||||
line_values = line._prepare_account_move_line(start_date, end_date)
|
||||
line_ids.append((0, 0, line_values))
|
||||
invoice_values = self._prepare_account_move(line_ids)
|
||||
invoice_id = (
|
||||
@@ -305,8 +308,10 @@ class SaleSubscription(models.Model):
|
||||
except AccessError:
|
||||
return self.env["sale.order"]
|
||||
line_ids = []
|
||||
start_date = self.recurring_next_date or self.date_start
|
||||
end_date = self._get_next_period_date_end(start_date, self.date)
|
||||
for line in self.sale_subscription_line_ids:
|
||||
line_values = line._prepare_sale_order_line()
|
||||
line_values = line._prepare_sale_order_line(start_date, end_date)
|
||||
line_ids.append((0, 0, line_values))
|
||||
values = self._prepare_sale_order(line_ids)
|
||||
order_id = self.env["sale.order"].sudo().create(values)
|
||||
@@ -431,6 +436,27 @@ class SaleSubscription(models.Model):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_next_period_date_end(
|
||||
self,
|
||||
next_period_date_start,
|
||||
max_date_end,
|
||||
):
|
||||
self.ensure_one()
|
||||
if not next_period_date_start:
|
||||
return False
|
||||
if max_date_end and next_period_date_start > max_date_end:
|
||||
return False
|
||||
next_period_date_end = (
|
||||
next_period_date_start
|
||||
+ self.template_id.get_relative_delta()
|
||||
- relativedelta(days=1)
|
||||
)
|
||||
if not max_date_end:
|
||||
return next_period_date_end
|
||||
if next_period_date_end > max_date_end:
|
||||
return max_date_end
|
||||
return next_period_date_end
|
||||
|
||||
def write(self, values):
|
||||
res = super().write(values)
|
||||
if "stage_id" in values:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 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 import _, api, fields, models
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
@@ -290,11 +290,11 @@ class SaleSubscriptionLine(models.Model):
|
||||
)
|
||||
return max(base_price, final_price)
|
||||
|
||||
def _prepare_sale_order_line(self):
|
||||
def _prepare_sale_order_line(self, start_date, end_date):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"product_id": self.product_id.id,
|
||||
"name": self.name,
|
||||
"name": self._generate_name(start_date, end_date),
|
||||
"product_uom_qty": self.product_uom_qty,
|
||||
"price_unit": self.price_unit,
|
||||
"discount": self.discount,
|
||||
@@ -303,7 +303,7 @@ class SaleSubscriptionLine(models.Model):
|
||||
"product_uom": self.product_id.uom_id.id,
|
||||
}
|
||||
|
||||
def _prepare_account_move_line(self):
|
||||
def _prepare_account_move_line(self, start_date, end_date):
|
||||
self.ensure_one()
|
||||
account = (
|
||||
self.product_id.property_account_income_id
|
||||
@@ -311,7 +311,7 @@ class SaleSubscriptionLine(models.Model):
|
||||
)
|
||||
return {
|
||||
"product_id": self.product_id.id,
|
||||
"name": self.name,
|
||||
"name": self._generate_name(start_date, end_date),
|
||||
"quantity": self.product_uom_qty,
|
||||
"price_unit": self.price_unit,
|
||||
"discount": self.discount,
|
||||
@@ -320,3 +320,43 @@ class SaleSubscriptionLine(models.Model):
|
||||
"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]
|
||||
|
||||
@@ -100,3 +100,16 @@ class SaleSubscriptionTemplate(models.Model):
|
||||
"type": "ir.actions.act_window",
|
||||
"domain": [("id", "in", self.product_ids.ids)],
|
||||
}
|
||||
|
||||
def get_relative_delta(self):
|
||||
self.ensure_one()
|
||||
rule_type = self.recurring_rule_type
|
||||
interval = self.recurring_interval
|
||||
if rule_type == "days":
|
||||
return relativedelta(days=interval)
|
||||
elif rule_type == "weeks":
|
||||
return relativedelta(weeks=interval)
|
||||
elif rule_type == "months":
|
||||
return relativedelta(months=interval)
|
||||
else:
|
||||
return relativedelta(years=interval)
|
||||
|
||||
@@ -15,6 +15,13 @@ class TestSubscriptionOCA(SavepointCase):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||
cls.portal_user = cls.env.ref("base.demo_user0")
|
||||
cls.line_placeholders = [
|
||||
"#START#",
|
||||
"#END#",
|
||||
"#INVOICEMONTHNAME#",
|
||||
"#INVOICEMONTHNUMBER#",
|
||||
"#INVOICEYEAR#",
|
||||
]
|
||||
cls.cash_journal = cls.env["account.journal"].search(
|
||||
[
|
||||
("type", "=", "cash"),
|
||||
@@ -181,15 +188,15 @@ class TestSubscriptionOCA(SavepointCase):
|
||||
"sale_subscription_id": cls.sub1.id,
|
||||
}
|
||||
)
|
||||
cls.sub_line21 = cls.create_sub_line(cls.sub2)
|
||||
cls.sub_line21 = cls.create_sub_line(cls.sub2, name="#START#")
|
||||
cls.sub_line22 = cls.create_sub_line(cls.sub2, cls.product_2.id)
|
||||
cls.sub_line31 = cls.create_sub_line(cls.sub3)
|
||||
cls.sub_line31 = cls.create_sub_line(cls.sub3, name="#END#")
|
||||
cls.sub_line32 = cls.create_sub_line(cls.sub3, cls.product_2.id)
|
||||
cls.sub_line41 = cls.create_sub_line(cls.sub4)
|
||||
cls.sub_line41 = cls.create_sub_line(cls.sub4, name="#INVOICEMONTHNAME#")
|
||||
cls.sub_line42 = cls.create_sub_line(cls.sub4, cls.product_2.id)
|
||||
cls.sub_line51 = cls.create_sub_line(cls.sub5)
|
||||
cls.sub_line51 = cls.create_sub_line(cls.sub5, name="#INVOICEMONTHNUMBER#")
|
||||
cls.sub_line52 = cls.create_sub_line(cls.sub5, cls.product_2.id)
|
||||
cls.sub_line71 = cls.create_sub_line(cls.sub7)
|
||||
cls.sub_line71 = cls.create_sub_line(cls.sub7, name="#INVOICEYEAR#")
|
||||
cls.sub_line72 = cls.create_sub_line(cls.sub7, cls.product_2.id)
|
||||
|
||||
cls.close_reason = cls.env["sale.subscription.close.reason"].create(
|
||||
@@ -263,14 +270,15 @@ class TestSubscriptionOCA(SavepointCase):
|
||||
return rec
|
||||
|
||||
@classmethod
|
||||
def create_sub_line(cls, sub, prod=None):
|
||||
ssl = cls.env["sale.subscription.line"].create(
|
||||
{
|
||||
"company_id": 1,
|
||||
"sale_subscription_id": sub.id,
|
||||
"product_id": prod or cls.product_1.id,
|
||||
}
|
||||
)
|
||||
def create_sub_line(cls, sub, prod=None, name=None):
|
||||
create_dict = {
|
||||
"company_id": 1,
|
||||
"sale_subscription_id": sub.id,
|
||||
"product_id": prod or cls.product_1.id,
|
||||
}
|
||||
if name:
|
||||
create_dict["name"] = name
|
||||
ssl = cls.env["sale.subscription.line"].create(create_dict)
|
||||
return ssl
|
||||
|
||||
@classmethod
|
||||
@@ -320,9 +328,11 @@ class TestSubscriptionOCA(SavepointCase):
|
||||
self.assertEqual(self.sub_line.discount, 0)
|
||||
res = self.sub_line._get_display_price(self.product_2)
|
||||
self.assertEqual(res, 38.25)
|
||||
sol_res = self.sub_line._prepare_sale_order_line()
|
||||
date_start = self.sub_line.sale_subscription_id.date_start
|
||||
date_end = self.sub_line.sale_subscription_id.date
|
||||
sol_res = self.sub_line._prepare_sale_order_line(date_start, date_end)
|
||||
self.assertIsInstance(sol_res, dict)
|
||||
move_res = self.sub_line._prepare_account_move_line()
|
||||
move_res = self.sub_line._prepare_account_move_line(date_start, date_end)
|
||||
self.assertIsInstance(move_res, dict)
|
||||
|
||||
def test_subscription_oca_sub_cron(self):
|
||||
@@ -593,13 +603,37 @@ class TestSubscriptionOCA(SavepointCase):
|
||||
res = self.sub_line.read(["discount"])
|
||||
self.assertEqual(res[0]["discount"], 0)
|
||||
|
||||
def get_converted_placeholders(self, placeholder_lines, date_from, date_to):
|
||||
return [line._insert_markers(date_from, date_to) for line in placeholder_lines]
|
||||
|
||||
def _collect_all_sub_test_results(self, subscription):
|
||||
test_res = []
|
||||
sale_order = subscription.create_sale_order()
|
||||
test_res.append(sale_order)
|
||||
move_id = subscription.create_invoice()
|
||||
test_res.append(move_id)
|
||||
lines_w_placeholder = subscription.sale_subscription_line_ids.filtered(
|
||||
lambda line: any(p == line.name for p in self.line_placeholders)
|
||||
)
|
||||
start_date = subscription.recurring_next_date or subscription.date_start
|
||||
end_date = subscription._get_next_period_date_end(start_date, subscription.date)
|
||||
# remove the lines with #INVOICEYEAR# if the end_date is not set
|
||||
if not end_date and "#INVOICEYEAR#" in lines_w_placeholder.mapped("name"):
|
||||
target = lines_w_placeholder.filtered(
|
||||
lambda line: line.name == "#INVOICEYEAR#"
|
||||
)
|
||||
lines_w_placeholder -= target
|
||||
res = subscription.manual_invoice()
|
||||
if lines_w_placeholder:
|
||||
markers = self.get_converted_placeholders(
|
||||
lines_w_placeholder, start_date, end_date
|
||||
)
|
||||
# all markers must be among the line names
|
||||
account_move_line_names = (
|
||||
self.env["account.move"].browse(res["res_id"]).line_ids.mapped("name")
|
||||
)
|
||||
result = all(m in account_move_line_names for m in markers)
|
||||
self.assertTrue(result)
|
||||
test_res.append(res["type"])
|
||||
inv_ids = self.env["account.move"].search(
|
||||
[("subscription_id", "=", subscription.id)]
|
||||
|
||||
@@ -192,6 +192,40 @@
|
||||
<field name="user_id" />
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
string="Legend (for the markers inside invoice lines description)"
|
||||
name="group_legend"
|
||||
>
|
||||
<p colspan="2">
|
||||
<strong>#START#</strong>
|
||||
: Start
|
||||
date
|
||||
of the
|
||||
invoiced period
|
||||
</p>
|
||||
<p colspan="2">
|
||||
<strong>#END#</strong>
|
||||
: End date
|
||||
of
|
||||
the
|
||||
invoiced period
|
||||
</p>
|
||||
<p colspan="2">
|
||||
<strong>#INVOICEMONTHNAME#</strong>
|
||||
: Invoice month name
|
||||
of
|
||||
the
|
||||
invoiced period
|
||||
</p>
|
||||
<p colspan="2">
|
||||
<strong
|
||||
>#INVOICEMONTHNUMBER#</strong>: Invoice month number of the period
|
||||
</p>
|
||||
<p colspan="2">
|
||||
<strong
|
||||
>#INVOICEYEAR#</strong>: Invoice year of the period
|
||||
</p>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user