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
|
return values
|
||||||
|
|
||||||
def create_invoice(self):
|
def create_invoice(self):
|
||||||
|
self.ensure_one()
|
||||||
if not self.env["account.move"].check_access_rights("create", False):
|
if not self.env["account.move"].check_access_rights("create", False):
|
||||||
try:
|
try:
|
||||||
self.check_access_rights("write")
|
self.check_access_rights("write")
|
||||||
@@ -284,8 +285,10 @@ class SaleSubscription(models.Model):
|
|||||||
except AccessError:
|
except AccessError:
|
||||||
return self.env["account.move"]
|
return self.env["account.move"]
|
||||||
line_ids = []
|
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:
|
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))
|
line_ids.append((0, 0, line_values))
|
||||||
invoice_values = self._prepare_account_move(line_ids)
|
invoice_values = self._prepare_account_move(line_ids)
|
||||||
invoice_id = (
|
invoice_id = (
|
||||||
@@ -305,8 +308,10 @@ class SaleSubscription(models.Model):
|
|||||||
except AccessError:
|
except AccessError:
|
||||||
return self.env["sale.order"]
|
return self.env["sale.order"]
|
||||||
line_ids = []
|
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:
|
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))
|
line_ids.append((0, 0, line_values))
|
||||||
values = self._prepare_sale_order(line_ids)
|
values = self._prepare_sale_order(line_ids)
|
||||||
order_id = self.env["sale.order"].sudo().create(values)
|
order_id = self.env["sale.order"].sudo().create(values)
|
||||||
@@ -431,6 +436,27 @@ class SaleSubscription(models.Model):
|
|||||||
return True
|
return True
|
||||||
return False
|
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):
|
def write(self, values):
|
||||||
res = super().write(values)
|
res = super().write(values)
|
||||||
if "stage_id" in values:
|
if "stage_id" in values:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Copyright 2023 Domatix - Carlos Martínez
|
# Copyright 2023 Domatix - Carlos Martínez
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
# 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
|
from odoo.tools.misc import get_lang
|
||||||
|
|
||||||
|
|
||||||
@@ -290,11 +290,11 @@ class SaleSubscriptionLine(models.Model):
|
|||||||
)
|
)
|
||||||
return max(base_price, final_price)
|
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()
|
self.ensure_one()
|
||||||
return {
|
return {
|
||||||
"product_id": self.product_id.id,
|
"product_id": self.product_id.id,
|
||||||
"name": self.name,
|
"name": self._generate_name(start_date, end_date),
|
||||||
"product_uom_qty": self.product_uom_qty,
|
"product_uom_qty": self.product_uom_qty,
|
||||||
"price_unit": self.price_unit,
|
"price_unit": self.price_unit,
|
||||||
"discount": self.discount,
|
"discount": self.discount,
|
||||||
@@ -303,7 +303,7 @@ class SaleSubscriptionLine(models.Model):
|
|||||||
"product_uom": self.product_id.uom_id.id,
|
"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()
|
self.ensure_one()
|
||||||
account = (
|
account = (
|
||||||
self.product_id.property_account_income_id
|
self.product_id.property_account_income_id
|
||||||
@@ -311,7 +311,7 @@ class SaleSubscriptionLine(models.Model):
|
|||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"product_id": self.product_id.id,
|
"product_id": self.product_id.id,
|
||||||
"name": self.name,
|
"name": self._generate_name(start_date, end_date),
|
||||||
"quantity": self.product_uom_qty,
|
"quantity": self.product_uom_qty,
|
||||||
"price_unit": self.price_unit,
|
"price_unit": self.price_unit,
|
||||||
"discount": self.discount,
|
"discount": self.discount,
|
||||||
@@ -320,3 +320,43 @@ class SaleSubscriptionLine(models.Model):
|
|||||||
"product_uom_id": self.product_id.uom_id.id,
|
"product_uom_id": self.product_id.uom_id.id,
|
||||||
"account_id": account.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",
|
"type": "ir.actions.act_window",
|
||||||
"domain": [("id", "in", self.product_ids.ids)],
|
"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()
|
super().setUpClass()
|
||||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||||
cls.portal_user = cls.env.ref("base.demo_user0")
|
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(
|
cls.cash_journal = cls.env["account.journal"].search(
|
||||||
[
|
[
|
||||||
("type", "=", "cash"),
|
("type", "=", "cash"),
|
||||||
@@ -181,15 +188,15 @@ class TestSubscriptionOCA(SavepointCase):
|
|||||||
"sale_subscription_id": cls.sub1.id,
|
"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_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_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_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_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.sub_line72 = cls.create_sub_line(cls.sub7, cls.product_2.id)
|
||||||
|
|
||||||
cls.close_reason = cls.env["sale.subscription.close.reason"].create(
|
cls.close_reason = cls.env["sale.subscription.close.reason"].create(
|
||||||
@@ -263,14 +270,15 @@ class TestSubscriptionOCA(SavepointCase):
|
|||||||
return rec
|
return rec
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_sub_line(cls, sub, prod=None):
|
def create_sub_line(cls, sub, prod=None, name=None):
|
||||||
ssl = cls.env["sale.subscription.line"].create(
|
create_dict = {
|
||||||
{
|
"company_id": 1,
|
||||||
"company_id": 1,
|
"sale_subscription_id": sub.id,
|
||||||
"sale_subscription_id": sub.id,
|
"product_id": prod or cls.product_1.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
|
return ssl
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -320,9 +328,11 @@ class TestSubscriptionOCA(SavepointCase):
|
|||||||
self.assertEqual(self.sub_line.discount, 0)
|
self.assertEqual(self.sub_line.discount, 0)
|
||||||
res = self.sub_line._get_display_price(self.product_2)
|
res = self.sub_line._get_display_price(self.product_2)
|
||||||
self.assertEqual(res, 38.25)
|
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)
|
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)
|
self.assertIsInstance(move_res, dict)
|
||||||
|
|
||||||
def test_subscription_oca_sub_cron(self):
|
def test_subscription_oca_sub_cron(self):
|
||||||
@@ -593,13 +603,37 @@ class TestSubscriptionOCA(SavepointCase):
|
|||||||
res = self.sub_line.read(["discount"])
|
res = self.sub_line.read(["discount"])
|
||||||
self.assertEqual(res[0]["discount"], 0)
|
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):
|
def _collect_all_sub_test_results(self, subscription):
|
||||||
test_res = []
|
test_res = []
|
||||||
sale_order = subscription.create_sale_order()
|
sale_order = subscription.create_sale_order()
|
||||||
test_res.append(sale_order)
|
test_res.append(sale_order)
|
||||||
move_id = subscription.create_invoice()
|
move_id = subscription.create_invoice()
|
||||||
test_res.append(move_id)
|
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()
|
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"])
|
test_res.append(res["type"])
|
||||||
inv_ids = self.env["account.move"].search(
|
inv_ids = self.env["account.move"].search(
|
||||||
[("subscription_id", "=", subscription.id)]
|
[("subscription_id", "=", subscription.id)]
|
||||||
|
|||||||
@@ -192,6 +192,40 @@
|
|||||||
<field name="user_id" />
|
<field name="user_id" />
|
||||||
</group>
|
</group>
|
||||||
</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>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user