Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contract_sale_generation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Contributors
- Florent THOMAS <florent.thomas@mind-and-go.com>
- Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
- Denis Roussel <denis.roussel@acsone.eu>
- Stéphane Mangin <stephane.mangin@acsone.eu>

Maintainers
-----------
Expand Down
2 changes: 1 addition & 1 deletion contract_sale_generation/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

{
"name": "Contracts Management - Recurring Sales",
"version": "19.0.1.0.0",
"version": "19.0.1.1.0",
"category": "Contract Management",
"license": "AGPL-3",
"author": "ACSONE SA/NV, PESOL, Odoo Community Association (OCA)",
Expand Down
14 changes: 14 additions & 0 deletions contract_sale_generation/migrations/19.0.1.1.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2026 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


def migrate(cr, version):
cr.execute(
"""
UPDATE sale_order sale
SET contract_id = contract_line.contract_id
FROM sale_order_line sale_line
JOIN contract_line ON contract_line.id = sale_line.contract_line_id
WHERE sale_line.order_id = sale.id
"""
)
41 changes: 21 additions & 20 deletions contract_sale_generation/models/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def _prepare_sale(self, date_ref):
"partner_id": self.partner_id,
"date_order": date_ref,
"origin": self.name,
"contract_id": self.id,
"company_id": self.company_id.id,
"user_id": self.partner_id.user_id.id,
}
Expand All @@ -37,11 +38,7 @@ def _prepare_sale(self, date_ref):

def _get_related_sales(self):
self.ensure_one()
sales = (
self.env["sale.order.line"]
.search([("contract_line_id", "in", self.contract_line_ids.ids)])
.mapped("order_id")
)
sales = self.env["sale.order"].search([("contract_id", "in", self.ids)])
return sales

def _compute_sale_count(self):
Expand Down Expand Up @@ -92,23 +89,27 @@ def _prepare_recurring_sales_values(self, date_ref=False):
# this use case is possible when recurring_create_invoice is
# called for a finished contract
continue
contract_lines = contract._get_lines_to_invoice(date_ref)
if not contract_lines:
continue
sale_values = contract._prepare_sale(date_ref)
for line in contract_lines:
sale_values.setdefault("order_line", [])
invoice_line_values = line._prepare_sale_line(
sale_values=sale_values,
)
if invoice_line_values:
sale_values["order_line"].append(
Command.create(invoice_line_values)
)
sales_values.append(sale_values)
contract_lines._update_last_date_invoiced()
sale_values = contract._prepare_recurring_sale_values(date_ref)
if sale_values:
sales_values.append(sale_values)
return sales_values

def _prepare_recurring_sale_values(self, date_ref):
self.ensure_one()
contract_lines = self._get_lines_to_invoice(date_ref)
if not contract_lines:
return {}
sale_values = self._prepare_sale(date_ref)
for line in contract_lines:
sale_values.setdefault("order_line", [])
invoice_line_values = line._prepare_sale_line(
sale_values=sale_values,
)
if invoice_line_values:
sale_values["order_line"].append(Command.create(invoice_line_values))
contract_lines._update_last_date_invoiced()
return sale_values

def _recurring_create_sale(self, date_ref=False):
sales_values = self._prepare_recurring_sales_values(date_ref)
sale_orders = self.env["sale.order"].create(sales_values)
Expand Down
6 changes: 2 additions & 4 deletions contract_sale_generation/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
class SaleOrder(models.Model):
_inherit = "sale.order"

contract_id = fields.Many2one("contract.contract", index=True)
contract_auto_confirm = fields.Boolean(
compute="_compute_contract_auto_confirm",
help="This is a technical field in order to know if the order should"
Expand All @@ -15,10 +16,7 @@ class SaleOrder(models.Model):

def _compute_contract_auto_confirm(self):
sale_auto_confirm = self.filtered(
lambda sale: any(
line.contract_line_id.contract_id.sale_autoconfirm
for line in sale.order_line
)
lambda sale: sale.contract_id.sale_autoconfirm
)
sale_auto_confirm.contract_auto_confirm = True
(self - sale_auto_confirm).contract_auto_confirm = False
1 change: 1 addition & 0 deletions contract_sale_generation/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
- Florent THOMAS \<florent.thomas@mind-and-go.com\>
- Serpent Consulting Services Pvt. Ltd. \<support@serpentcs.com\>
- Denis Roussel \<denis.roussel@acsone.eu\>
- Stéphane Mangin \<stephane.mangin@acsone.eu\>
1 change: 1 addition & 0 deletions contract_sale_generation/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ <h3><a class="toc-backref" href="#toc-entry-5">Contributors</a></h3>
<li>Florent THOMAS &lt;<a class="reference external" href="mailto:florent.thomas&#64;mind-and-go.com">florent.thomas&#64;mind-and-go.com</a>&gt;</li>
<li>Serpent Consulting Services Pvt. Ltd. &lt;<a class="reference external" href="mailto:support&#64;serpentcs.com">support&#64;serpentcs.com</a>&gt;</li>
<li>Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</li>
<li>Stéphane Mangin &lt;<a class="reference external" href="mailto:stephane.mangin&#64;acsone.eu">stephane.mangin&#64;acsone.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
26 changes: 26 additions & 0 deletions contract_sale_generation/tests/test_contract_sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Copyright 2017 Angel Moya <angel.moya@pesol.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from unittest.mock import patch

from odoo import Command
from odoo.exceptions import ValidationError

Expand Down Expand Up @@ -136,6 +138,30 @@ def test__prepare_recurring_sales_values_no_contract_lines(self):
)
self.assertEqual(a_contract_with_no_lines._prepare_recurring_sales_values(), [])

def test__prepare_recurring_sale_values_no_sale_line(self):
with patch.object(
type(self.contract_line), "_prepare_sale_line", return_value={}
):
sale_values = self.contract._prepare_recurring_sale_values(
self.contract.recurring_next_date
)
self.assertEqual(sale_values["order_line"], [])

def test_related_sales_without_contract_line(self):
with patch.object(
type(self.contract_line), "_prepare_sale_line", return_value={}
):
sales = self.contract._recurring_create_sale()
self.assertEqual(self.contract._get_related_sales(), sales)

def test_autoconfirm_without_contract_line(self):
self.contract.sale_autoconfirm = True
with patch.object(
type(self.contract_line), "_prepare_sale_line", return_value={}
):
sales = self.contract._recurring_create_sale()
self.assertEqual(sales.state, "sale")

def test__prepare_sale_line_vals_with_order_id(self):
order = self.contract.recurring_create_sale()[0]
recurring_next_date = self.contract.recurring_next_date
Expand Down
5 changes: 4 additions & 1 deletion contract_sale_generation/views/contract.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='generation_type']" position="after">
<xpath
expr="//group[@name='recurring_type']/field[@name='generation_type']"
position="after"
>
Comment on lines +7 to +10

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue with placement otherwize

<field invisible="generation_type != 'sale'" name="sale_autoconfirm" />
</xpath>
<xpath expr="//button[@name='recurring_create_invoice']" position="before">
Expand Down
Loading