diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index fdcf42cadf9..3275c0d541f 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -4343,6 +4343,35 @@ class AccountMove(models.Model): self.ensure_one() return f"{self.name.replace('/', '_')}_proforma.pdf" + def _prepare_edi_vals_to_export(self): + ''' The purpose of this helper is to prepare values in order to export an invoice through the EDI system. + This includes the computation of the tax details for each invoice line that could be very difficult to + handle regarding the computation of the base amount. + + :return: A python dict containing default pre-processed values. + ''' + self.ensure_one() + + res = { + 'record': self, + 'balance_multiplicator': -1 if self.is_inbound() else 1, + 'invoice_line_vals_list': [], + } + + # Invoice lines details. + for index, line in enumerate(self.invoice_line_ids.filtered(lambda line: line.display_type == 'product'), start=1): + line_vals = line._prepare_edi_vals_to_export() + line_vals['index'] = index + res['invoice_line_vals_list'].append(line_vals) + + # Totals. + res.update({ + 'total_price_subtotal_before_discount': sum(x['price_subtotal_before_discount'] for x in res['invoice_line_vals_list']), + 'total_price_discount': sum(x['price_discount'] for x in res['invoice_line_vals_list']), + }) + + return res + # ------------------------------------------------------------------------- # TOOLING # ------------------------------------------------------------------------- diff --git a/addons/account/models/account_move_line.py b/addons/account/models/account_move_line.py index ebea9f0709f..048294a04d0 100644 --- a/addons/account/models/account_move_line.py +++ b/addons/account/models/account_move_line.py @@ -2989,6 +2989,35 @@ class AccountMoveLine(models.Model): 'template': '/account/static/xls/aml_import_template.xlsx' }] + def _prepare_edi_vals_to_export(self): + ''' The purpose of this helper is the same as '_prepare_edi_vals_to_export' but for a single invoice line. + This includes the computation of the tax details for each invoice line or the management of the discount. + Indeed, in some EDI, we need to provide extra values depending the discount such as: + - the discount as an amount instead of a percentage. + - the price_unit but after subtraction of the discount. + + :return: A python dict containing default pre-processed values. + ''' + self.ensure_one() + + if self.discount == 100.0: + gross_price_subtotal = self.currency_id.round(self.price_unit * self.quantity) + else: + gross_price_subtotal = self.currency_id.round(self.price_subtotal / (1 - self.discount / 100.0)) + + res = { + 'line': self, + 'price_unit_after_discount': self.currency_id.round(self.price_unit * (1 - (self.discount / 100.0))), + 'price_subtotal_before_discount': gross_price_subtotal, + 'price_subtotal_unit': self.currency_id.round(self.price_subtotal / self.quantity) if self.quantity else 0.0, + 'price_total_unit': self.currency_id.round(self.price_total / self.quantity) if self.quantity else 0.0, + 'price_discount': gross_price_subtotal - self.price_subtotal, + 'price_discount_unit': (gross_price_subtotal - self.price_subtotal) / self.quantity if self.quantity else 0.0, + 'gross_price_total_unit': self.currency_id.round(gross_price_subtotal / self.quantity) if self.quantity else 0.0, + 'unece_uom_code': self.product_id.product_tmpl_id.uom_id._get_unece_code(), + } + return res + # ------------------------------------------------------------------------- # PUBLIC ACTIONS # ------------------------------------------------------------------------- diff --git a/addons/account/models/uom_uom.py b/addons/account/models/uom_uom.py index 0496dc73ddd..38866a417ff 100644 --- a/addons/account/models/uom_uom.py +++ b/addons/account/models/uom_uom.py @@ -13,3 +13,34 @@ class UoM(models.Model): def _compute_fiscal_country_codes(self): for record in self: record.fiscal_country_codes = ",".join(self.env.companies.mapped("account_fiscal_country_id.code")) + + def _get_unece_code(self): + """ Returns the UNECE code used for international trading for corresponding to the UoM as per + https://unece.org/fileadmin/DAM/cefact/recommendations/rec20/rec20_rev3_Annex2e.pdf""" + mapping = { + 'uom.product_uom_unit': 'C62', + 'uom.product_uom_dozen': 'DZN', + 'uom.product_uom_kgm': 'KGM', + 'uom.product_uom_gram': 'GRM', + 'uom.product_uom_day': 'DAY', + 'uom.product_uom_hour': 'HUR', + 'uom.product_uom_ton': 'TNE', + 'uom.product_uom_meter': 'MTR', + 'uom.product_uom_km': 'KTM', + 'uom.product_uom_cm': 'CMT', + 'uom.product_uom_litre': 'LTR', + 'uom.product_uom_lb': 'LBR', + 'uom.product_uom_oz': 'ONZ', + 'uom.product_uom_inch': 'INH', + 'uom.product_uom_foot': 'FOT', + 'uom.product_uom_mile': 'SMI', + 'uom.product_uom_floz': 'OZA', + 'uom.product_uom_qt': 'QT', + 'uom.product_uom_gal': 'GLL', + 'uom.product_uom_cubic_meter': 'MTQ', + 'uom.product_uom_cubic_inch': 'INQ', + 'uom.product_uom_cubic_foot': 'FTQ', + } + xml_ids = self._get_external_ids().get(self.id, []) + matches = list(set(xml_ids) & set(mapping.keys())) + return matches and mapping[matches[0]] or 'C62' diff --git a/addons/account_edi/models/__init__.py b/addons/account_edi/models/__init__.py index aad034164bb..60c9adadf7d 100644 --- a/addons/account_edi/models/__init__.py +++ b/addons/account_edi/models/__init__.py @@ -6,4 +6,3 @@ from . import account_edi_format from . import account_edi_document from . import ir_actions_report from . import ir_attachment -from . import uom diff --git a/addons/account_edi/models/account_move.py b/addons/account_edi/models/account_move.py index 359d47e17df..45463090be9 100644 --- a/addons/account_edi/models/account_move.py +++ b/addons/account_edi/models/account_move.py @@ -223,35 +223,6 @@ class AccountMove(models.Model): grouping_key_generator=grouping_key_generator, ) - def _prepare_edi_vals_to_export(self): - ''' The purpose of this helper is to prepare values in order to export an invoice through the EDI system. - This includes the computation of the tax details for each invoice line that could be very difficult to - handle regarding the computation of the base amount. - - :return: A python dict containing default pre-processed values. - ''' - self.ensure_one() - - res = { - 'record': self, - 'balance_multiplicator': -1 if self.is_inbound() else 1, - 'invoice_line_vals_list': [], - } - - # Invoice lines details. - for index, line in enumerate(self.invoice_line_ids.filtered(lambda line: line.display_type == 'product'), start=1): - line_vals = line._prepare_edi_vals_to_export() - line_vals['index'] = index - res['invoice_line_vals_list'].append(line_vals) - - # Totals. - res.update({ - 'total_price_subtotal_before_discount': sum(x['price_subtotal_before_discount'] for x in res['invoice_line_vals_list']), - 'total_price_discount': sum(x['price_discount'] for x in res['invoice_line_vals_list']), - }) - - return res - def _is_ready_to_be_sent(self): # OVERRIDE # Prevent a mail to be sent to the customer if the EDI document is not sent. @@ -429,39 +400,3 @@ class AccountMove(models.Model): if document.state in {'sent', 'cancelled'}: zipfile_obj.writestr(document.display_name, document.attachment_id.raw) return buffer.getvalue() - -class AccountMoveLine(models.Model): - _inherit = 'account.move.line' - - #################################################### - # Export Electronic Document - #################################################### - - def _prepare_edi_vals_to_export(self): - ''' The purpose of this helper is the same as '_prepare_edi_vals_to_export' but for a single invoice line. - This includes the computation of the tax details for each invoice line or the management of the discount. - Indeed, in some EDI, we need to provide extra values depending the discount such as: - - the discount as an amount instead of a percentage. - - the price_unit but after subtraction of the discount. - - :return: A python dict containing default pre-processed values. - ''' - self.ensure_one() - - if self.discount == 100.0: - gross_price_subtotal = self.currency_id.round(self.price_unit * self.quantity) - else: - gross_price_subtotal = self.currency_id.round(self.price_subtotal / (1 - self.discount / 100.0)) - - res = { - 'line': self, - 'price_unit_after_discount': self.currency_id.round(self.price_unit * (1 - (self.discount / 100.0))), - 'price_subtotal_before_discount': gross_price_subtotal, - 'price_subtotal_unit': self.currency_id.round(self.price_subtotal / self.quantity) if self.quantity else 0.0, - 'price_total_unit': self.currency_id.round(self.price_total / self.quantity) if self.quantity else 0.0, - 'price_discount': gross_price_subtotal - self.price_subtotal, - 'price_discount_unit': (gross_price_subtotal - self.price_subtotal) / self.quantity if self.quantity else 0.0, - 'gross_price_total_unit': self.currency_id.round(gross_price_subtotal / self.quantity) if self.quantity else 0.0, - 'unece_uom_code': self.product_id.product_tmpl_id.uom_id._get_unece_code(), - } - return res diff --git a/addons/account_edi/models/uom.py b/addons/account_edi/models/uom.py deleted file mode 100644 index 7c28ff4429a..00000000000 --- a/addons/account_edi/models/uom.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -from odoo import models - - -class UoM(models.Model): - _inherit = 'uom.uom' - - def _get_unece_code(self): - """ Returns the UNECE code used for international trading for corresponding to the UoM as per - https://unece.org/fileadmin/DAM/cefact/recommendations/rec20/rec20_rev3_Annex2e.pdf""" - mapping = { - 'uom.product_uom_unit': 'C62', - 'uom.product_uom_dozen': 'DZN', - 'uom.product_uom_kgm': 'KGM', - 'uom.product_uom_gram': 'GRM', - 'uom.product_uom_day': 'DAY', - 'uom.product_uom_hour': 'HUR', - 'uom.product_uom_ton': 'TNE', - 'uom.product_uom_meter': 'MTR', - 'uom.product_uom_km': 'KTM', - 'uom.product_uom_cm': 'CMT', - 'uom.product_uom_litre': 'LTR', - 'uom.product_uom_lb': 'LBR', - 'uom.product_uom_oz': 'ONZ', - 'uom.product_uom_inch': 'INH', - 'uom.product_uom_foot': 'FOT', - 'uom.product_uom_mile': 'SMI', - 'uom.product_uom_floz': 'OZA', - 'uom.product_uom_qt': 'QT', - 'uom.product_uom_gal': 'GLL', - 'uom.product_uom_cubic_meter': 'MTQ', - 'uom.product_uom_cubic_inch': 'INQ', - 'uom.product_uom_cubic_foot': 'FTQ', - } - xml_ids = self._get_external_ids().get(self.id, []) - matches = list(set(xml_ids) & set(mapping.keys())) - return matches and mapping[matches[0]] or 'C62'