From 5ccd0a5b8d4d4e717d262413253271012f85e7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Marques?= Date: Fri, 12 Feb 2021 12:29:09 +0000 Subject: [PATCH] [IMP] intrastat_product: add support for Brexit + small performance improvement + remove universal hs_code constaint Add support for post-Brexit VAT numbers with latest python-stdnum version Remove use of country_id.intrastat Add 'vat' field on computation and declaration lines with a simple validity check Add 'partner_id' field on computation lines Prevent back to draft when an XML export is present Remove the universal constaint applied to the hs_codes for countries in the "Europe" list, as discussed in https://github.com/OCA/intrastat-extrastat/pull/116#discussion_r569735555 Co-authored-by: Alexis de Lattre [UPD] Update intrastat_product.pot [UPD] README.rst --- intrastat_product/__manifest__.py | 1 + intrastat_product/i18n/intrastat_product.pot | 197 ++++++++++++++---- intrastat_product/models/account_move.py | 10 +- intrastat_product/models/hs_code.py | 24 +-- .../models/intrastat_product_declaration.py | 162 +++++++++++--- .../report/intrastat_product_report_xls.py | 10 + .../static/description/index.html | 2 +- .../views/intrastat_product_declaration.xml | 19 +- 8 files changed, 313 insertions(+), 112 deletions(-) diff --git a/intrastat_product/__manifest__.py b/intrastat_product/__manifest__.py index d442ff4..4c7c415 100644 --- a/intrastat_product/__manifest__.py +++ b/intrastat_product/__manifest__.py @@ -21,6 +21,7 @@ "report_xlsx_helper", ], "excludes": ["account_intrastat"], + "external_dependencies": {"python": ["python-stdnum>=1.16"]}, "data": [ "security/intrastat_security.xml", "security/ir.model.access.csv", diff --git a/intrastat_product/i18n/intrastat_product.pot b/intrastat_product/i18n/intrastat_product.pot index 3827354..27c6f27 100644 --- a/intrastat_product/i18n/intrastat_product.pot +++ b/intrastat_product/i18n/intrastat_product.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -128,6 +128,11 @@ msgstr "" msgid "Activity State" msgstr "" +#. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + #. module: intrastat_product #: model:intrastat.transport_mode,name:intrastat_product.intrastat_transport_4 msgid "Air" @@ -196,6 +201,12 @@ msgstr "" msgid "Back to Draft" msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "Before going back to draft, you must delete the XML export." +msgstr "" + #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_region__code #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_transaction__code @@ -235,11 +246,6 @@ msgstr "" msgid "Company Country Code" msgstr "" -#. module: intrastat_product -#: model:ir.model.fields,field_description:intrastat_product.field_res_config_settings__country_code -msgid "Company Country code" -msgstr "" - #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__company_currency_id #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__company_currency_id @@ -424,6 +430,11 @@ msgstr "" msgid "Default Transport Mode" msgstr "" +#. module: intrastat_product +#: model_terms:ir.ui.view,arch_db:intrastat_product.intrastat_product_declaration_view_form +msgid "Delete XML Export" +msgstr "" + #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_region__description #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_transaction__description @@ -438,7 +449,9 @@ msgid "Destination Country" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,help:intrastat_product.field_account_bank_statement_line__src_dest_country_id #: model:ir.model.fields,help:intrastat_product.field_account_move__src_dest_country_id +#: model:ir.model.fields,help:intrastat_product.field_account_payment__src_dest_country_id msgid "Destination country for dispatches. Origin country for arrivals." msgstr "" @@ -450,7 +463,10 @@ msgid "Dispatches" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_move__display_name #: model:ir.model.fields,field_description:intrastat_product.field_account_move_intrastat_line__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_account_move_line__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_hs_code__display_name #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__display_name #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__display_name #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__display_name @@ -459,6 +475,11 @@ msgstr "" #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_transport_mode__display_name #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_unit__display_name #: model:ir.model.fields,field_description:intrastat_product.field_report_intrastat_product_product_declaration_xls__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_res_company__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_res_config_settings__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_sale_order__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_stock_location__display_name +#: model:ir.model.fields,field_description:intrastat_product.field_stock_warehouse__display_name msgid "Display Name" msgstr "" @@ -519,6 +540,11 @@ msgstr "" msgid "Followers (Partners)" msgstr "" +#. module: intrastat_product +#: model:ir.model.fields,help:intrastat_product.field_intrastat_product_declaration__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + #. module: intrastat_product #: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 #: model_terms:ir.ui.view,arch_db:intrastat_product.intrastat_product_declaration_view_form @@ -570,7 +596,10 @@ msgid "H.S. Codes" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_move__id #: model:ir.model.fields,field_description:intrastat_product.field_account_move_intrastat_line__id +#: model:ir.model.fields,field_description:intrastat_product.field_account_move_line__id +#: model:ir.model.fields,field_description:intrastat_product.field_hs_code__id #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__id #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__id #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__id @@ -579,6 +608,11 @@ msgstr "" #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_transport_mode__id #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_unit__id #: model:ir.model.fields,field_description:intrastat_product.field_report_intrastat_product_product_declaration_xls__id +#: model:ir.model.fields,field_description:intrastat_product.field_res_company__id +#: model:ir.model.fields,field_description:intrastat_product.field_res_config_settings__id +#: model:ir.model.fields,field_description:intrastat_product.field_sale_order__id +#: model:ir.model.fields,field_description:intrastat_product.field_stock_location__id +#: model:ir.model.fields,field_description:intrastat_product.field_stock_warehouse__id msgid "ID" msgstr "" @@ -645,28 +679,9 @@ msgid "Intrastat Code %s:" msgstr "" #. module: intrastat_product -#: code:addons/intrastat_product/models/hs_code.py:0 -#, python-format -msgid "" -"Intrastat Codes should contain 8 digits. This is not the case for Intrastat " -"Code '%s' which has %d digits." -msgstr "" - -#. module: intrastat_product -#: code:addons/intrastat_product/models/hs_code.py:0 -#, python-format -msgid "" -"Intrastat Codes should only contain digits. This is not the case for code " -"'%s'." -msgstr "" - -#. module: intrastat_product -#: model:ir.model.fields,field_description:intrastat_product.field_account_move__intrastat_country -msgid "Intrastat Country" -msgstr "" - -#. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__intrastat #: model:ir.model.fields,field_description:intrastat_product.field_account_move__intrastat +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__intrastat #: model:ir.model.fields,field_description:intrastat_product.field_res_company__intrastat #: model:ir.model.fields,field_description:intrastat_product.field_res_config_settings__intrastat #: model:ir.model.fields,field_description:intrastat_product.field_sale_order__intrastat @@ -765,7 +780,9 @@ msgid "Intrastat Transaction" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__intrastat_transaction_id #: model:ir.model.fields,field_description:intrastat_product.field_account_move__intrastat_transaction_id +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__intrastat_transaction_id #: model_terms:ir.ui.view,arch_db:intrastat_product.intrastat_transaction_form msgid "Intrastat Transaction Type" msgstr "" @@ -777,7 +794,9 @@ msgstr "" #. module: intrastat_product #: model:ir.model,name:intrastat_product.model_intrastat_transport_mode +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__intrastat_transport_id #: model:ir.model.fields,field_description:intrastat_product.field_account_move__intrastat_transport_id +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__intrastat_transport_id #: model_terms:ir.ui.view,arch_db:intrastat_product.intrastat_transport_mode_form msgid "Intrastat Transport Mode" msgstr "" @@ -794,12 +813,16 @@ msgstr "" #. module: intrastat_product #: model:ir.model,name:intrastat_product.model_account_move_intrastat_line +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__intrastat_line_ids #: model:ir.model.fields,field_description:intrastat_product.field_account_move__intrastat_line_ids +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__intrastat_line_ids msgid "Intrastat declaration details" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,help:intrastat_product.field_account_bank_statement_line__intrastat_transaction_id #: model:ir.model.fields,help:intrastat_product.field_account_move__intrastat_transaction_id +#: model:ir.model.fields,help:intrastat_product.field_account_payment__intrastat_transaction_id msgid "Intrastat nature of transaction" msgstr "" @@ -851,7 +874,7 @@ msgstr "" #. module: intrastat_product #: model:ir.model,name:intrastat_product.model_account_move -msgid "Journal Entries" +msgid "Journal Entry" msgstr "" #. module: intrastat_product @@ -866,7 +889,10 @@ msgid "Kg" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_move____last_update #: model:ir.model.fields,field_description:intrastat_product.field_account_move_intrastat_line____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_account_move_line____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_hs_code____last_update #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line____last_update #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration____last_update #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line____last_update @@ -875,6 +901,11 @@ msgstr "" #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_transport_mode____last_update #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_unit____last_update #: model:ir.model.fields,field_description:intrastat_product.field_report_intrastat_product_product_declaration_xls____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_res_company____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_res_config_settings____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_sale_order____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_stock_location____last_update +#: model:ir.model.fields,field_description:intrastat_product.field_stock_warehouse____last_update msgid "Last Modified on" msgstr "" @@ -923,6 +954,20 @@ msgstr "" msgid "Missing Intrastat Code on product %s. " msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "Missing VAT Number on partner '%s'" +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "" +"Missing country on invoice partner '%s' or on the delivery address (partner " +"'%s'). " +msgstr "" + #. module: intrastat_product #: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 #, python-format @@ -1033,25 +1078,61 @@ msgstr "" msgid "Number of unread messages" msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "" +"On invoice '%s', the source/destination country is '%s' which is not part of" +" the European Union." +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "" +"On invoice '%s', the source/destination country is United-Kingdom and the " +"fiscal position is '%s'. Make sure that the fiscal position is right. If the" +" origin/destination is Northern Ireland, please set the VAT number of the " +"partner '%s' in Odoo with its new VAT number starting with 'XI' following " +"Brexit." +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "" +"On invoice '%s', the source/destination country is United-Kingdom, the " +"fiscal position is '%s' and the partner's VAT number is '%s'. Make sure that" +" the fiscal position is right. If the origin/destination is Northern " +"Ireland, please update the VAT number of the partner '%s' in Odoo with its " +"new VAT number starting with 'XI' following Brexit." +msgstr "" + #. module: intrastat_product #: model_terms:ir.ui.view,arch_db:intrastat_product.view_move_form msgid "Origin Region" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,help:intrastat_product.field_account_bank_statement_line__src_dest_region_id #: model:ir.model.fields,help:intrastat_product.field_account_move__src_dest_region_id +#: model:ir.model.fields,help:intrastat_product.field_account_payment__src_dest_region_id msgid "" "Origin region for dispatches, destination region for arrivals. This field is" " used for the Intrastat Declaration." msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__src_dest_country_id #: model:ir.model.fields,field_description:intrastat_product.field_account_move__src_dest_country_id +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__src_dest_country_id msgid "Origin/Destination Country" msgstr "" #. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_account_bank_statement_line__src_dest_region_id #: model:ir.model.fields,field_description:intrastat_product.field_account_move__src_dest_region_id +#: model:ir.model.fields,field_description:intrastat_product.field_account_payment__src_dest_region_id msgid "Origin/Destination Region" msgstr "" @@ -1067,6 +1148,13 @@ msgid "" "under their own power, e.g. aircraft, lorries, boats, etc.)" msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/report/intrastat_product_report_xls.py:0 +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__partner_id +#, python-format +msgid "Partner" +msgstr "" + #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__year_month msgid "Period" @@ -1199,13 +1287,6 @@ msgstr "" msgid "Search Intrastat Transport Modes" msgstr "" -#. module: intrastat_product -#: model:ir.model.fields,help:intrastat_product.field_intrastat_product_computation_line__type -#: model:ir.model.fields,help:intrastat_product.field_intrastat_product_declaration__type -#: model:ir.model.fields,help:intrastat_product.field_intrastat_product_declaration_line__type -msgid "Select the declaration type." -msgstr "" - #. module: intrastat_product #: model:ir.model.fields,help:intrastat_product.field_intrastat_unit__uom_id msgid "" @@ -1280,10 +1361,10 @@ msgid "The Declaration Action has been set to 'nihil'." msgstr "" #. module: intrastat_product -#: model:ir.model.fields,help:intrastat_product.field_res_config_settings__country_code -msgid "" -"The ISO country code in two chars. \n" -"You can use this field for quick search." +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "The VAT number '%s' is invalid." msgstr "" #. module: intrastat_product @@ -1386,9 +1467,9 @@ msgid "Transport Modes" msgstr "" #. module: intrastat_product -#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__type -#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__type -#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__type +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__declaration_type +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__declaration_type +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__declaration_type #: model_terms:ir.ui.view,arch_db:intrastat_product.intrastat_product_declaration_view_search msgid "Type" msgstr "" @@ -1418,6 +1499,28 @@ msgstr "" msgid "Used to keep track of changes" msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/report/intrastat_product_report_xls.py:0 +#, python-format +msgid "VAT" +msgstr "" + +#. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__vat +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration_line__vat +msgid "VAT Number" +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/models/intrastat_product_declaration.py:0 +#, python-format +msgid "" +"VAT number of partner '%s' is '%s'. If this partner is from Northern " +"Ireland, his VAT number should be updated to his new VAT number starting " +"with 'XI' following Brexit. If this partner is from Great Britain, maybe the" +" fiscal position was wrong on invoice '%s' (the fiscal position was '%s')." +msgstr "" + #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_computation_line__valid #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__valid @@ -1449,9 +1552,19 @@ msgstr "" #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__xml_attachment_id +msgid "XML Attachment" +msgstr "" + +#. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__xml_attachment_datas msgid "XML Export" msgstr "" +#. module: intrastat_product +#: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__xml_attachment_name +msgid "XML Filename" +msgstr "" + #. module: intrastat_product #: model:ir.model.fields,field_description:intrastat_product.field_intrastat_product_declaration__year msgid "Year" diff --git a/intrastat_product/models/account_move.py b/intrastat_product/models/account_move.py index 78fd522..256cffb 100644 --- a/intrastat_product/models/account_move.py +++ b/intrastat_product/models/account_move.py @@ -25,15 +25,10 @@ class AccountMove(models.Model): src_dest_country_id = fields.Many2one( comodel_name="res.country", string="Origin/Destination Country", - compute="_compute_intrastat_country", + compute="_compute_src_dest_country_id", store=True, help="Destination country for dispatches. Origin country for " "arrivals.", ) - intrastat_country = fields.Boolean( - compute="_compute_intrastat_country", - string="Intrastat Country", - store=True, - ) src_dest_region_id = fields.Many2one( comodel_name="intrastat.region", string="Origin/Destination Region", @@ -52,13 +47,12 @@ class AccountMove(models.Model): ) @api.depends("partner_shipping_id.country_id", "partner_id.country_id") - def _compute_intrastat_country(self): + def _compute_src_dest_country_id(self): for inv in self: country = inv.partner_shipping_id.country_id or inv.partner_id.country_id if not country: country = inv.company_id.country_id inv.src_dest_country_id = country.id - inv.intrastat_country = country.intrastat @api.model def _default_src_dest_region_id(self): diff --git a/intrastat_product/models/hs_code.py b/intrastat_product/models/hs_code.py index cb9af06..a54ae43 100644 --- a/intrastat_product/models/hs_code.py +++ b/intrastat_product/models/hs_code.py @@ -3,8 +3,7 @@ # @author Alexis de Lattre # @author Luc de Meyer -from odoo import _, api, fields, models -from odoo.exceptions import ValidationError +from odoo import fields, models class HSCode(models.Model): @@ -13,24 +12,3 @@ class HSCode(models.Model): intrastat_unit_id = fields.Many2one( comodel_name="intrastat.unit", string="Intrastat Supplementary Unit" ) - - @api.constrains("local_code") - def _hs_code(self): - if self.company_id.country_id.intrastat: - if not self.local_code.isdigit(): - raise ValidationError( - _( - "Intrastat Codes should only contain digits. " - "This is not the case for code '%s'." - ) - % self.local_code - ) - if len(self.local_code) != 8: - raise ValidationError( - _( - "Intrastat Codes should " - "contain 8 digits. This is not the case for " - "Intrastat Code '%s' which has %d digits." - ) - % (self.local_code, len(self.local_code)) - ) diff --git a/intrastat_product/models/intrastat_product_declaration.py b/intrastat_product/models/intrastat_product_declaration.py index 2ee4d14..a13a5c8 100644 --- a/intrastat_product/models/intrastat_product_declaration.py +++ b/intrastat_product/models/intrastat_product_declaration.py @@ -7,6 +7,7 @@ import logging from datetime import date from dateutil.relativedelta import relativedelta +from stdnum.vatin import is_valid from odoo import _, api, fields, models from odoo.exceptions import RedirectWarning, UserError, ValidationError @@ -241,15 +242,71 @@ class IntrastatProductDeclaration(models.Model): msg, action.id, _("Go to Accounting Configuration Settings screen") ) - def _get_partner_country(self, inv_line, notedict): - country = ( - inv_line.move_id.src_dest_country_id - or inv_line.move_id.partner_id.country_id - ) - if not country.intrastat: - country = False - elif country == self.company_id.country_id: - country = False + def _get_partner_country(self, inv_line, notedict, eu_countries): + inv = inv_line.move_id + country = inv.src_dest_country_id or inv.partner_id.country_id + if not country: + line_notes = [ + _( + "Missing country on invoice partner '%s' " + "or on the delivery address (partner '%s'). " + ) + % ( + inv.partner_id.display_name, + inv.partner_shipping_id + and inv.partner_shipping_id.display_name + or "-", + ) + ] + self._format_line_note(inv_line, notedict, line_notes) + else: + if country not in eu_countries and country.code != "GB": + line_notes = [ + _( + "On invoice '%s', the source/destination country " + "is '%s' which is not part of the European Union." + ) + % (inv.name, country.name) + ] + self._format_line_note(inv_line, notedict, line_notes) + if country and country.code == "GB" and self.year >= "2021": + vat = inv.commercial_partner_id.vat + if not vat: + line_notes = [ + _( + "On invoice '%s', the source/destination country " + "is United-Kingdom and the fiscal position is '%s'. " + "Make sure that the fiscal position is right. If " + "the origin/destination is Northern Ireland, please " + "set the VAT number of the partner '%s' in Odoo with " + "its new VAT number starting with 'XI' following Brexit." + ) + % ( + inv.name, + inv.fiscal_position_id.display_name, + inv.commercial_partner_id.display_name, + ) + ] + self._format_line_note(inv_line, notedict, line_notes) + elif not vat.startswith("XI"): + line_notes = [ + _( + "On invoice '%s', the source/destination country " + "is United-Kingdom, the fiscal position is '%s' and " + "the partner's VAT number is '%s'. " + "Make sure that the fiscal position is right. If " + "the origin/destination is Northern Ireland, please " + "update the VAT number of the partner '%s' in Odoo with " + "its new VAT number starting with 'XI' following Brexit." + ) + % ( + inv.name, + inv.fiscal_position_id.display_name, + vat, + inv.commercial_partner_id.display_name, + ) + ] + self._format_line_note(inv_line, notedict, line_notes) return country def _get_intrastat_transaction(self, inv_line, notedict): @@ -338,7 +395,7 @@ class IntrastatProductDeclaration(models.Model): ) % (source_uom.name, product.display_name) ] - self._note += self._format_line_note(inv_line, notedict, line_notes) + self._format_line_note(inv_line, notedict, line_notes) return weight, suppl_unit_qty return weight, suppl_unit_qty @@ -421,6 +478,39 @@ class IntrastatProductDeclaration(models.Model): def _get_product_origin_country(self, inv_line, notedict): return inv_line.product_id.origin_country_id + def _get_vat(self, inv_line, notedict): + vat = False + inv = inv_line.move_id + if self.declaration_type == "dispatches": + vat = inv.commercial_partner_id.vat + if vat: + if vat.startswith("GB"): + line_notes = [ + _( + "VAT number of partner '%s' is '%s'. If this partner " + "is from Northern Ireland, his VAT number should be " + "updated to his new VAT number starting with 'XI' " + "following Brexit. If this partner is from Great Britain, " + "maybe the fiscal position was wrong on invoice '%s' " + "(the fiscal position was '%s')." + ) + % ( + inv.commercial_partner_id.display_name, + vat, + inv.name, + inv.fiscal_position_id.display_name, + ) + ] + self._format_line_note(inv_line, notedict, line_notes) + + else: + line_notes = [ + _("Missing VAT Number on partner '%s'") + % inv.commercial_partner_id.display_name + ] + self._format_line_note(inv_line, notedict, line_notes) + return vat + def _update_computation_line_vals(self, inv_line, line_vals, notedict): """ placeholder for localization modules """ @@ -516,6 +606,7 @@ class IntrastatProductDeclaration(models.Model): "Product Unit of Measure" ) accessory_costs = self.company_id.intrastat_accessory_costs + eu_countries = self.env.ref("base.europe").country_ids self._gather_invoices_init(notedict) domain = self._prepare_invoice_domain() @@ -559,22 +650,9 @@ class IntrastatProductDeclaration(models.Model): ) continue - partner_country = self._get_partner_country(inv_line, notedict) - if not partner_country: - line_notes = [ - _( - "Missing country on invoice partner '%s' " - "or on the delivery address (partner '%s'). " - ) - % ( - invoice.partner_id.display_name, - invoice.partner_shipping_id - and invoice.partner_shipping_id.display_name - or "-", - ) - ] - self._format_line_note(inv_line, notedict, line_notes) - continue + partner_country = self._get_partner_country( + inv_line, notedict, eu_countries + ) if inv_intrastat_line: hs_code = inv_intrastat_line.hs_code_id @@ -622,6 +700,8 @@ class IntrastatProductDeclaration(models.Model): region = self._get_region(inv_line, notedict) + vat = self._get_vat(inv_line, notedict) + line_vals = { "parent_id": self.id, "invoice_line_id": inv_line.id, @@ -635,6 +715,7 @@ class IntrastatProductDeclaration(models.Model): "transaction_id": intrastat_transaction.id, "product_origin_country_id": product_origin_country.id or False, "region_id": region and region.id or False, + "vat": vat, } # extended declaration @@ -686,7 +767,6 @@ class IntrastatProductDeclaration(models.Model): def action_gather(self): self.ensure_one() self.message_post(body=_("Generate Lines from Invoices")) - self._check_generate_lines() notedict = { "note": "", "line_nbr": 0, @@ -739,6 +819,7 @@ class IntrastatProductDeclaration(models.Model): "region": computation_line.region_id.id or False, "product_origin_country": computation_line.product_origin_country_id.id or False, + "vat": computation_line.vat or False, } def group_line_hashcode(self, computation_line): @@ -758,6 +839,7 @@ class IntrastatProductDeclaration(models.Model): "parent_id": computation_line.parent_id.id, "product_origin_country_id": computation_line.product_origin_country_id.id, "amount_company_currency": 0.0, + "vat": computation_line.vat, } for field in fields_to_sum: vals[field] = 0.0 @@ -867,6 +949,8 @@ class IntrastatProductDeclaration(models.Model): "suppl_unit_qty", "suppl_unit", "transport", + "vat", + "partner_id", "invoice", ] @@ -884,6 +968,7 @@ class IntrastatProductDeclaration(models.Model): "suppl_unit_qty", "suppl_unit", "transport", + "vat", ] @api.model @@ -898,6 +983,11 @@ class IntrastatProductDeclaration(models.Model): self.write({"state": "done"}) def back2draft(self): + for decl in self: + if decl.xml_attachment_id: + raise UserError( + _("Before going back to draft, you must delete the XML export.") + ) self.write({"state": "draft"}) @@ -924,6 +1014,9 @@ class IntrastatProductComputationLine(models.Model): invoice_id = fields.Many2one( "account.move", related="invoice_line_id.move_id", string="Invoice" ) + partner_id = fields.Many2one( + related="invoice_line_id.move_id.commercial_partner_id", string="Partner" + ) declaration_line_id = fields.Many2one( "intrastat.product.declaration.line", string="Declaration Line", readonly=True ) @@ -978,6 +1071,7 @@ class IntrastatProductComputationLine(models.Model): string="Country of Origin of the Product", help="Country of origin of the product i.e. product 'made in ____'", ) + vat = fields.Char(string="VAT Number") @api.depends("transport_id") def _compute_check_validity(self): @@ -985,6 +1079,12 @@ class IntrastatProductComputationLine(models.Model): for this in self: this.valid = True + @api.constrains("vat") + def _check_vat(self): + for this in self: + if this.vat and not is_valid(this.vat): + raise ValidationError(_("The VAT number '%s' is invalid.") % this.vat) + # TODO: product_id is a readonly related field 'invoice_line_id.product_id' # so the onchange is non-sense. Either we convert product_id to a regular # field or we keep it a related field and we remove this onchange @@ -1027,7 +1127,6 @@ class IntrastatProductDeclarationLine(models.Model): "res.country", string="Country", help="Country of Origin/Destination", - domain=[("intrastat", "=", True)], ) hs_code_id = fields.Many2one("hs.code", string="Intrastat Code") intrastat_unit_id = fields.Many2one( @@ -1058,3 +1157,10 @@ class IntrastatProductDeclarationLine(models.Model): string="Country of Origin of the Product", help="Country of origin of the product i.e. product 'made in ____'", ) + vat = fields.Char(string="VAT Number") + + @api.constrains("vat") + def _check_vat(self): + for this in self: + if this.vat and not is_valid(this.vat): + raise ValidationError(_("The VAT number '%s' is invalid.") % this.vat) diff --git a/intrastat_product/report/intrastat_product_report_xls.py b/intrastat_product/report/intrastat_product_report_xls.py index 4f8949b..48ccb26 100644 --- a/intrastat_product/report/intrastat_product_report_xls.py +++ b/intrastat_product/report/intrastat_product_report_xls.py @@ -145,6 +145,16 @@ class IntrastatProductDeclarationXlsx(models.AbstractModel): "line": {"value": self._render("line.region_id.name or ''")}, "width": 28, }, + "vat": { + "header": {"type": "string", "value": self._("VAT")}, + "line": {"value": self._render("line.vat or ''")}, + "width": 20, + }, + "partner_id": { + "header": {"type": "string", "value": self._("Partner")}, + "line": {"value": self._render("line.partner_id.display_name or ''")}, + "width": 28, + }, "invoice": { "header": {"type": "string", "value": self._("Invoice")}, "line": {"value": self._render("line.invoice_id.name")}, diff --git a/intrastat_product/static/description/index.html b/intrastat_product/static/description/index.html index 809f693..58bd746 100644 --- a/intrastat_product/static/description/index.html +++ b/intrastat_product/static/description/index.html @@ -3,7 +3,7 @@ - + Intrastat Product