-
-
Notifications
You must be signed in to change notification settings - Fork 687
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by grindtildeath
- Loading branch information
Showing
12 changed files
with
318 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
from . import account_move | ||
from . import res_company | ||
from . import res_config_settings | ||
from . import res_partner | ||
from . import sale_order |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) | ||
from odoo import _, api, models | ||
from odoo.exceptions import UserError | ||
|
||
|
||
class AccountMove(models.Model): | ||
_inherit = "account.move" | ||
|
||
def _get_ordered_invoice_lines(self): | ||
"""Sort invoice lines according to the section ordering""" | ||
return self.invoice_line_ids.sorted( | ||
key=self.env["account.move.line"]._get_section_ordering() | ||
) | ||
|
||
|
||
class AccountMoveLine(models.Model): | ||
_inherit = "account.move.line" | ||
|
||
def _get_section_group(self): | ||
"""Return the section group to be used for a single invoice line""" | ||
self.ensure_one() | ||
return self.mapped(self._get_section_grouping()) | ||
|
||
def _get_section_grouping(self): | ||
"""Defines the grouping relation from the invoice lines to be used. | ||
Meant to be overriden, in order to allow custom grouping. | ||
""" | ||
invoice_section_grouping = self.company_id.invoice_section_grouping | ||
if invoice_section_grouping == "sale_order": | ||
return "sale_line_ids.order_id" | ||
raise UserError(_("Unrecognized invoice_section_grouping")) | ||
|
||
@api.model | ||
def _get_section_ordering(self): | ||
"""Function to sort invoice lines before grouping""" | ||
return lambda r: r.mapped(r._get_section_grouping()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) | ||
from odoo import fields, models | ||
|
||
|
||
class ResCompany(models.Model): | ||
_inherit = "res.company" | ||
|
||
invoice_section_name_scheme = fields.Char( | ||
help="This is the name of the sections on invoices when generated from " | ||
"sales orders. Keep empty to use default. You can use a python " | ||
"expression with the 'object' (representing sale order) and 'time'" | ||
" variables." | ||
) | ||
|
||
invoice_section_grouping = fields.Selection( | ||
[ | ||
("sale_order", "Group by sale Order"), | ||
], | ||
help="Defines object used to group invoice lines", | ||
default="sale_order", | ||
required=True, | ||
) |
18 changes: 18 additions & 0 deletions
18
account_invoice_section_sale_order/models/res_config_settings.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) | ||
from odoo import fields, models | ||
|
||
|
||
class ResConfigSettings(models.TransientModel): | ||
_inherit = "res.config.settings" | ||
|
||
invoice_section_name_scheme = fields.Char( | ||
related="company_id.invoice_section_name_scheme", | ||
readonly=False, | ||
) | ||
|
||
invoice_section_grouping = fields.Selection( | ||
related="company_id.invoice_section_grouping", | ||
readonly=False, | ||
required=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) | ||
from odoo import fields, models | ||
|
||
|
||
class ResPartner(models.Model): | ||
_inherit = "res.partner" | ||
|
||
invoice_section_name_scheme = fields.Char( | ||
help="This is the name of the sections on invoices when generated from " | ||
"sales orders. Keep empty to use default. You can use a python " | ||
"expression with the 'object' (representing sale order) and 'time'" | ||
" variables." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,84 @@ | ||
# Copyright 2020 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) | ||
from collections import OrderedDict | ||
|
||
from odoo import models | ||
from odoo.tools.safe_eval import safe_eval, time | ||
|
||
|
||
class SaleOrder(models.Model): | ||
_inherit = "sale.order" | ||
|
||
def _create_invoices(self, grouped=False, final=False, date=None): | ||
"""Add sections by sale order in the invoice line. | ||
"""Add sections by groups in the invoice line. | ||
Order the invoicing lines by sale order and add lines section with | ||
the sale order name. | ||
Only do this for invoices targetting multiple sale order | ||
Order the invoicing lines by groups and add lines section with | ||
the group name. | ||
Only do this for invoices targetting multiple groups | ||
""" | ||
invoice_ids = super()._create_invoices(grouped=grouped, final=final, date=date) | ||
for invoice in invoice_ids: | ||
if len(invoice.line_ids.mapped("sale_line_ids.order_id.id")) == 1: | ||
if ( | ||
len(invoice.line_ids.mapped(invoice.line_ids._get_section_grouping())) | ||
== 1 | ||
): | ||
continue | ||
so = None | ||
sequence = 10 | ||
move_lines = invoice._get_ordered_invoice_lines() | ||
# Group move lines according to their sale order | ||
section_grouping_matrix = OrderedDict() | ||
for move_line in move_lines: | ||
group = move_line._get_section_group() | ||
section_grouping_matrix.setdefault(group, []).append(move_line.id) | ||
# Prepare section lines for each group | ||
section_lines = [] | ||
lines = self._get_ordered_invoice_lines(invoice) | ||
for line in lines: | ||
if line.sale_line_ids.order_id and so != line.sale_line_ids.order_id: | ||
so = line.sale_line_ids.order_id | ||
for group, move_line_ids in section_grouping_matrix.items(): | ||
if group: | ||
section_lines.append( | ||
( | ||
0, | ||
0, | ||
{ | ||
"name": so._get_saleorder_section_name(), | ||
"name": group._get_invoice_section_name(), | ||
"display_type": "line_section", | ||
"sequence": sequence, | ||
# see test: test_create_invoice_with_default_journal | ||
# forcing the account_id is needed to avoid | ||
# incorrect default value | ||
"account_id": False, | ||
# see test: test_create_invoice_with_currency | ||
# if the currency is not set with the right value | ||
# the total amount will be wrong | ||
# because all line do not have the same currency | ||
"currency_id": invoice.currency_id.id, | ||
}, | ||
) | ||
) | ||
sequence += 10 | ||
if line.display_type == "line_section": | ||
# add extra indent for existing SO Sections | ||
line.name = f"- {line.name}" | ||
line.sequence = sequence | ||
sequence += 10 | ||
for move_line in self.env["account.move.line"].browse(move_line_ids): | ||
if move_line.display_type == "line_section": | ||
# add extra indent for existing SO Sections | ||
move_line.name = f"- {move_line.name}" | ||
move_line.sequence = sequence | ||
sequence += 10 | ||
invoice.line_ids = section_lines | ||
|
||
return invoice_ids | ||
|
||
def _get_ordered_invoice_lines(self, invoice): | ||
return invoice.invoice_line_ids.sorted( | ||
key=lambda r: r.sale_line_ids.order_id.id | ||
) | ||
|
||
def _get_saleorder_section_name(self): | ||
def _get_invoice_section_name(self): | ||
"""Returns the text for the section name.""" | ||
self.ensure_one() | ||
if self.client_order_ref: | ||
naming_scheme = ( | ||
self.partner_invoice_id.invoice_section_name_scheme | ||
or self.company_id.invoice_section_name_scheme | ||
) | ||
if naming_scheme: | ||
return safe_eval(naming_scheme, {"object": self, "time": time}) | ||
elif self.client_order_ref: | ||
return "{} - {}".format(self.name, self.client_order_ref or "") | ||
else: | ||
return self.name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
To allow customization of the name of the section, user should be part of group | ||
`Allow customization of invoice section name from sale order`. | ||
|
||
A naming scheme can be defined per company on the configuration page in the | ||
`Customer Invoices` section, or per partner in the accounting page, using | ||
python expression. | ||
|
||
The object used for the grouping can be customized by installing extra module | ||
(e.g. `account_invoice_section_picking`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<odoo> | ||
<record id="group_sale_order_invoice_section_name" model="res.groups"> | ||
<field | ||
name="name" | ||
>Allow customization of invoice section name from sale order</field> | ||
<field name="category_id" ref="base.module_category_usability" /> | ||
</record> | ||
</odoo> |
Oops, something went wrong.