Skip to content

Commit 884b4d8

Browse files
TDuphuctranfxvn
authored andcommitted
[13.0][ADD] account_invoice_section_sale_order
Description from the readme : When invoicing multiple sale orders at the same time, sale orders may be grouped by customer into a single invoice. Unfortunately when this happens, it is hard to know which invoice line belongs to which sale order. This module helps by grouping invoicing lines into sections with the name of the targeted sale order. This is only done when an invoice targets multiple sale order.
1 parent cbc45c5 commit 884b4d8

File tree

8 files changed

+192
-0
lines changed

8 files changed

+192
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
2+
3+
from . import models
4+
from . import tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2020 Camptocamp
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Acccount Invoice Section Sale Order",
5+
"version": "13.0.1.0.0",
6+
"summary": "For invoices targetting multiple sale order add"
7+
"sections with sale order name.",
8+
"author": "Camptocamp, Odoo Community Association (OCA)",
9+
"website": "https://github.com/OCA/account-invoicing",
10+
"license": "AGPL-3",
11+
"category": "Accounting & Finance",
12+
"depends": ["account", "sale"],
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import sale_order
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright 2020 Camptocamp SA
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
3+
4+
from odoo import models
5+
6+
7+
class SaleOrder(models.Model):
8+
_inherit = "sale.order"
9+
10+
def _create_invoices(self, grouped=False, final=False):
11+
"""Add sections by sale order in the invoice line.
12+
13+
Order the invoicing lines by sale order and add lines section with
14+
the sale order name.
15+
Only do this for invoices targetting multiple sale order
16+
"""
17+
invoice_ids = super()._create_invoices(grouped=grouped, final=final)
18+
for invoice in invoice_ids:
19+
if len(invoice.line_ids.mapped("sale_line_ids.order_id.id")) == 1:
20+
continue
21+
so = None
22+
sequence = 10
23+
section_lines = []
24+
lines = invoice.line_ids.sorted(
25+
key=lambda r: r.sale_line_ids.order_id.id
26+
).filtered(lambda r: not r.exclude_from_invoice_tab)
27+
for line in lines:
28+
if line.sale_line_ids.order_id and so != line.sale_line_ids.order_id:
29+
so = line.sale_line_ids.order_id
30+
section_lines.append(
31+
(
32+
0,
33+
0,
34+
{
35+
"name": so._get_saleorder_section_name(),
36+
"display_type": "line_section",
37+
"sequence": sequence,
38+
},
39+
)
40+
)
41+
sequence += 10
42+
line.sequence = sequence
43+
sequence += 10
44+
invoice.line_ids = section_lines
45+
46+
return invoice_ids
47+
48+
def _get_saleorder_section_name(self):
49+
"""Returns the text for the section name."""
50+
self.ensure_one()
51+
if self.client_order_ref:
52+
return "{} - {}".format(self.name, self.client_order_ref or "")
53+
else:
54+
return self.name
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
* `Camptocamp <https://www.camptocamp.com>`_
2+
3+
* Thierry Ducrest <thierry.ducrest@camptocamp.com>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
When invoicing multiple sale orders at the same time, sale orders may be grouped
2+
by customer into a single invoice. Unfortunately when this happens, it is hard
3+
to know which invoice line belongs to which sale order.
4+
5+
This module helps by grouping invoicing lines into sections with the name of the
6+
targeted sale order.
7+
This is only done when an invoice targets multiple sale order.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import test_invoice_group_by_sale_order
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright 2020 Camptocamp SA
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
3+
4+
from odoo.tests.common import SavepointCase
5+
6+
7+
class TestInvoiceGroupBySaleOrder(SavepointCase):
8+
@classmethod
9+
def setUpClass(cls):
10+
super().setUpClass()
11+
cls.partner_1 = cls.env.ref("base.res_partner_1")
12+
cls.product_1 = cls.env.ref("product.product_product_1")
13+
cls.product_1.invoice_policy = "order"
14+
cls.order1_p1 = cls.env["sale.order"].create(
15+
{
16+
"partner_id": cls.partner_1.id,
17+
"partner_shipping_id": cls.partner_1.id,
18+
"partner_invoice_id": cls.partner_1.id,
19+
"client_order_ref": "ref123",
20+
"order_line": [
21+
(
22+
0,
23+
0,
24+
{
25+
"name": "order 1 line 1",
26+
"product_id": cls.product_1.id,
27+
"price_unit": 20,
28+
"product_uom_qty": 1,
29+
"product_uom": cls.product_1.uom_id.id,
30+
},
31+
),
32+
(
33+
0,
34+
0,
35+
{
36+
"name": "order 1 line 2",
37+
"product_id": cls.product_1.id,
38+
"price_unit": 20,
39+
"product_uom_qty": 1,
40+
"product_uom": cls.product_1.uom_id.id,
41+
},
42+
),
43+
],
44+
}
45+
)
46+
cls.order1_p1.action_confirm()
47+
cls.order2_p1 = cls.env["sale.order"].create(
48+
{
49+
"partner_id": cls.partner_1.id,
50+
"partner_shipping_id": cls.partner_1.id,
51+
"partner_invoice_id": cls.partner_1.id,
52+
"order_line": [
53+
(
54+
0,
55+
0,
56+
{
57+
"name": "order 2 line 1",
58+
"product_id": cls.product_1.id,
59+
"price_unit": 20,
60+
"product_uom_qty": 1,
61+
"product_uom": cls.product_1.uom_id.id,
62+
},
63+
),
64+
(
65+
0,
66+
0,
67+
{
68+
"name": "order 2 line 2",
69+
"product_id": cls.product_1.id,
70+
"price_unit": 20,
71+
"product_uom_qty": 1,
72+
"product_uom": cls.product_1.uom_id.id,
73+
},
74+
),
75+
],
76+
}
77+
)
78+
cls.order2_p1.action_confirm()
79+
80+
def test_create_invoice(self):
81+
""" Check invoice is generated with sale order sections."""
82+
result = {
83+
0: "".join([self.order1_p1.name, " - ", self.order1_p1.client_order_ref]),
84+
1: "order 1 line 1",
85+
2: "order 1 line 2",
86+
3: self.order2_p1.name,
87+
4: "order 2 line 1",
88+
5: "order 2 line 2",
89+
}
90+
invoice_ids = (self.order1_p1 + self.order2_p1)._create_invoices()
91+
lines = (
92+
invoice_ids[0]
93+
.line_ids.sorted("sequence")
94+
.filtered(lambda r: not r.exclude_from_invoice_tab)
95+
)
96+
for idx, line in enumerate(lines):
97+
self.assertEqual(line.name, result[idx])
98+
99+
def test_create_invoice_no_section(self):
100+
""" Check invoice for only one sale order
101+
102+
No need to create sections
103+
104+
"""
105+
invoice_id = (self.order1_p1)._create_invoices()
106+
line_sections = invoice_id.line_ids.filtered(
107+
lambda r: r.display_type == "line_section"
108+
)
109+
self.assertEqual(len(line_sections), 0)

0 commit comments

Comments
 (0)