Repository: OCA/intrastat-extrastat (language: python)

Issue:
change m2m table name to avoid naming conflicts with other modules
cf. https://github.com/OCA/intrastat-extrastat/issues/97
14.0 mig : invoice domain should be based on fiscal position in stead of country
Up till now the default domain to select intrastat transactions is based upon invoices to/from EU countries.
I propose that we change in 14.0 the logic to be based upon the "Intra EU" fiscal position.

On the Belgian market transactions subject to the 'intrastat' declaration are also subject to the 'intracommunity' tax declaration.
In the 13.0 version of the Belgium localisation module I already replaced the domain query, cf. 
https://github.com/Noviat/noviat-apps/blob/012c9a254b101c405126b1c0ce5276a0a9c16d9e/l10n_be_intrastat_product/models/l10n_be_intrastat_product_declaration.py#L219

But since these rules are decided on an european level, this should be applicable for all EU countries.
As a consequence I propose that for the 14.0 migration we add an 'intrastat' boolean to the fiscal position and base the domain on invoices with fiscal positions marked as 'intrastat'. In the localisation modules we can add the logic to set this flag automatically on the standard Intra EU fiscal position.

To give a concrete example why the country tabel is wrong:
If you ship goods to a customer without VAT number in an EU country that this shipment must not be included in the intrastat declaration.



Discussion / hints:

Fix patch:
diff --git a/intrastat_base/README.rst b/intrastat_base/README.rst
new file mode 100644
index 000000000..86532cdcf
--- /dev/null
+++ b/intrastat_base/README.rst
@@ -0,0 +1,118 @@
+========================
+Intrastat Reporting Base
+========================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+   !! This file is generated by oca-gen-addon-readme !!
+   !! changes will be overwritten.                   !!
+   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+    :target: https://odoo-community.org/page/development-status
+    :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+    :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fintrastat--extrastat-lightgray.png?logo=github
+    :target: https://github.com/OCA/intrastat-extrastat/tree/15.0/intrastat_base
+    :alt: OCA/intrastat-extrastat
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+    :target: https://translation.odoo-community.org/projects/intrastat-extrastat-15-0/intrastat-extrastat-15-0-intrastat_base
+    :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+    :target: https://runbot.odoo-community.org/runbot/227/15.0
+    :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5| 
+
+This module contains common functions for the intrastat reporting and
+should be used in combination with the generic reporting module
+*intrastat_product* and with the country-specific reporting modules such
+as:
+
+- *l10n_fr_intrastat_service*:
+  the module for the *Déclaration Européenne des Services* (DES) for France
+- *l10n_fr_intrastat_product*:
+  the module for the *Déclaration d'Echange de Biens* (DEB) for France
+- *l10n_be_intrastat_product*:
+  the module for the Intrastat Declaration for Belgium.
+
+**Table of contents**
+
+.. contents::
+   :local:
+
+Installation
+============
+
+WARNING:
+
+This module conflicts with the module *account_intrastat* from Odoo Enterprise.
+If you have already installed the module *account_intrastat*,
+you should uninstall it first before installing this module.
+
+Usage
+=====
+
+This module adds an intrastat property on fiscal positions.
+
+With this module, the country field on partners becomes a required field.
+
+It adds an *Intrastat* section on the *Invoicing* configuration page.
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues <https://github.com/OCA/intrastat-extrastat/issues>`_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+`feedback <https://github.com/OCA/intrastat-extrastat/issues/new?body=module:%20intrastat_base%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* ACSONE SA/NV
+* Akretion
+* Noviat
+
+Contributors
+~~~~~~~~~~~~
+
+* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
+* Luc De Meyer, Noviat <info@noviat.com>
+* Kumar Aberer, brain-tec AG <kumar.aberer@braintec-group.com>
+* Andrea Stirpe <a.stirpe@onestein.nl>
+* Denis Roussel <denis.roussel@acsone.eu>
+
+Maintainers
+~~~~~~~~~~~
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+   :alt: Odoo Community Association
+   :target: https://odoo-community.org
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+.. |maintainer-alexis-via| image:: https://github.com/alexis-via.png?size=40px
+    :target: https://github.com/alexis-via
+    :alt: alexis-via
+.. |maintainer-luc-demeyer| image:: https://github.com/luc-demeyer.png?size=40px
+    :target: https://github.com/luc-demeyer
+    :alt: luc-demeyer
+
+Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
+
+|maintainer-alexis-via| |maintainer-luc-demeyer| 
+
+This module is part of the `OCA/intrastat-extrastat <https://github.com/OCA/intrastat-extrastat/tree/15.0/intrastat_base>`_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py
new file mode 100644
index 000000000..aee8895e7
--- /dev/null
+++ b/intrastat_base/__init__.py
@@ -0,0 +1,2 @@
+from . import models
+from . import wizards
diff --git a/intrastat_base/__manifest__.py b/intrastat_base/__manifest__.py
new file mode 100644
index 000000000..8bd97fb41
--- /dev/null
+++ b/intrastat_base/__manifest__.py
@@ -0,0 +1,27 @@
+# Copyright 2011-2022 Akretion (http://www.akretion.com)
+# Copyright 2018-2022 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
+# Copyright 2009-2022 Noviat (http://www.noviat.com)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+    "name": "Intrastat Reporting Base",
+    "version": "16.0.1.0.0",
+    "category": "Intrastat",
+    "license": "AGPL-3",
+    "summary": "Base module for Intrastat reporting",
+    "author": "ACSONE SA/NV, Akretion,Noviat,Odoo Community Association (OCA)",
+    "maintainers": ["alexis-via", "luc-demeyer"],
+    "website": "https://github.com/OCA/intrastat-extrastat",
+    "depends": ["base_vat", "account"],
+    "excludes": ["account_intrastat"],
+    "data": [
+        "views/product_template.xml",
+        "views/res_partner.xml",
+        "views/res_config_settings.xml",
+        "views/intrastat.xml",
+        "views/account_fiscal_position.xml",
+        "views/account_fiscal_position_template.xml",
+    ],
+    "demo": ["demo/intrastat_demo.xml"],
+    "installable": True,
+}
diff --git a/intrastat_base/demo/intrastat_demo.xml b/intrastat_base/demo/intrastat_demo.xml
new file mode 100644
index 000000000..f19b28539
--- /dev/null
+++ b/intrastat_base/demo/intrastat_demo.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2011-2022 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo noupdate="1">
+    <record id="base.main_partner" model="res.partner">
+        <field name="vat">FR58441019213</field>
+    </record>
+    <!-- Create a few partners from several EU countries
+    with real/valid VAT number -->
+    <record id="noviat" model="res.partner">
+        <field name="name">Noviat</field>
+        <field name="is_company">1</field>
+        <field name="website">https://www.noviat.com</field>
+        <field name="street">Avenue de Rusatiralaan 1</field>
+        <field name="city">Ganshoren</field>
+        <field name="zip">1083</field>
+        <field name="country_id" ref="base.be" />
+        <field name="vat">BE0820512013</field>
+    </record>
+    <record id="acsone" model="res.partner">
+        <field name="name">Acsone</field>
+        <field name="is_company">1</field>
+        <field name="website">https://www.acsone.eu</field>
+        <field name="street">Drève Richelle, 167</field>
+        <field name="city">Waterloo</field>
+        <field name="zip">1410</field>
+        <field name="country_id" ref="base.be" />
+        <field name="vat">BE0835207216</field>
+    </record>
+    <record id="tecnativa" model="res.partner">
+        <field name="name">Tecnativa</field>
+        <field name="is_company">1</field>
+        <field name="website">https://www.tecnativa.com</field>
+        <field name="street">Calle Tormos 1-A, 25</field>
+        <field name="city">Alicante</field>
+        <field name="zip">03008</field>
+        <field name="country_id" ref="base.es" />
+        <field name="vat">ESB87530432</field>
+    </record>
+    <record id="forgeflow" model="res.partner">
+        <field name="name">ForgeFlow</field>
+        <field name="is_company">1</field>
+        <field name="website">https://www.forgeflow.com</field>
+        <field name="street">Rosselló 319, 6-1</field>
+        <field name="city">Barcelona</field>
+        <field name="zip">08037</field>
+        <field name="country_id" ref="base.es" />
+        <field name="vat">ESB66676008</field>
+    </record>
+    <record id="akretion_france" model="res.partner">
+        <field name="name">Akretion France</field>
+        <field name="is_company">1</field>
+        <field name="website">https://www.akretion.com</field>
+        <field name="street">27 rue Henri Rolland</field>
+        <field name="city">Villeurbanne</field>
+        <field name="zip">69100</field>
+        <field name="country_id" ref="base.fr" />
+        <field name="vat">FR86792377731</field>
+    </record>
+    <record id="shipping_costs_exclude" model="product.product">
+        <field name="name">Shipping costs</field>
+        <field name="default_code">SHIP_S</field>
+        <field name="type">service</field>
+        <field name="categ_id" ref="product.product_category_all" />
+        <field name="list_price">30</field>
+        <field name="is_accessory_cost" eval="True" />
+    </record>
+</odoo>
diff --git a/intrastat_base/i18n/fr.po b/intrastat_base/i18n/fr.po
new file mode 100644
index 000000000..d1db811a5
--- /dev/null
+++ b/intrastat_base/i18n/fr.po
@@ -0,0 +1,277 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# 	* intrastat_base
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 11.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-12-29 09:52+0000\n"
+"PO-Revision-Date: 2021-07-04 21:48+0000\n"
+"Last-Translator: Alexis de Lattre <alexis@via.ecp.fr>\n"
+"Language-Team: \n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: Weblate 4.3.2\n"
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_product_product__is_accessory_cost
+#: model:ir.model.fields,help:intrastat_base.field_product_template__is_accessory_cost
+msgid ""
+"Activate this option for shipping costs, packaging costs and all services "
+"related to the sale of products. This option is used for Intrastat reports."
+msgstr ""
+"Activer cette option pour les frais de port, les frais d'emballage et tous "
+"les services associés à la vente de produits. Cette option est utilisée pour "
+"la DEB et la DES."
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_account_fiscal_position_template__intrastat
+msgid ""
+"Check this if you want to generate intrastat declarations withthe created "
+"fiscal position"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_company
+msgid "Companies"
+msgstr "Sociétés"
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_config_settings
+msgid "Config Settings"
+msgstr "Configuration"
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_partner
+msgid "Contact"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_fiscal_position
+msgid "Fiscal Position"
+msgstr "Position fiscale"
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_account_fiscal_position__intrastat
+#: model:ir.model.fields,field_description:intrastat_base.field_account_fiscal_position_template__intrastat
+#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root
+#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_config_root
+#: model_terms:ir.ui.view,arch_db:intrastat_base.product_template_form_view
+#: model_terms:ir.ui.view,arch_db:intrastat_base.view_intrastat_res_config_settings
+msgid "Intrastat"
+msgstr "DEB/DES"
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_account_bank_statement_line__intrastat_fiscal_position
+#: model:ir.model.fields,field_description:intrastat_base.field_account_move__intrastat_fiscal_position
+#: model:ir.model.fields,field_description:intrastat_base.field_account_payment__intrastat_fiscal_position
+msgid "Intrastat Fiscal Position"
+msgstr "Position fiscale intrastat"
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_product_product__is_accessory_cost
+#: model:ir.model.fields,field_description:intrastat_base.field_product_template__is_accessory_cost
+msgid "Is Accessory Cost"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_move
+msgid "Journal Entry"
+msgstr "Pièce comptable"
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_res_company__intrastat_remind_user_ids
+#: model:ir.model.fields,help:intrastat_base.field_res_config_settings__intrastat_remind_user_ids
+msgid ""
+"List of Odoo users who will receive a notification to remind them about the "
+"Intrastat declaration."
+msgstr "Liste d'utilisateurs Odoo qui recevront un rappel pour la DEB/DES."
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_res_company__intrastat_email_list
+msgid "List of emails of Users Receiving the Intrastat Reminder"
+msgstr "Liste des emails des utilisateurs qui reçoivent le rappel DEB/DES"
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_company.py:0
+#, python-format
+msgid "Missing e-mail address on user '%s'."
+msgstr "Adresse e-mail manquante pour l'utilisateur '%s'."
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_product_template
+msgid "Product Template"
+msgstr "Modèle d'article"
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_partner.py:0
+#, python-format
+msgid "Programming Error when calling '_get_intrastat_country_code()"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_account_bank_statement_line__intrastat_fiscal_position
+#: model:ir.model.fields,help:intrastat_base.field_account_fiscal_position__intrastat
+#: model:ir.model.fields,help:intrastat_base.field_account_move__intrastat_fiscal_position
+#: model:ir.model.fields,help:intrastat_base.field_account_payment__intrastat_fiscal_position
+msgid ""
+"Set to True if the invoices with this fiscal position should be taken into "
+"account for the generation of the intrastat reports."
+msgstr ""
+"Activer si les factures ayant cette position fiscale doivent être "
+"sélectionnées pour la génération des rapports intrastat."
+
+#. module: intrastat_base
+#: model:product.product,name:intrastat_base.shipping_costs_exclude
+#: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template
+msgid "Shipping costs"
+msgstr "Frais de port"
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_fiscal_position_template
+msgid "Template for Fiscal Position"
+msgstr "Modèle de position fiscale"
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/product_template.py:0
+#, python-format
+msgid ""
+"The option 'Is accessory cost?' should only be activated on 'Service' "
+"products. You have activated this option for the product '{product_name}' "
+"which is configured with type '{product_type}'."
+msgstr ""
+
+#. module: intrastat_base
+#: model:product.product,uom_name:intrastat_base.shipping_costs_exclude
+#: model:product.template,uom_name:intrastat_base.shipping_costs_exclude_product_template
+msgid "Units"
+msgstr "Unités"
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_company.py:0
+#, python-format
+msgid "Unknown Error"
+msgstr "Erreur inconnue"
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_res_company__intrastat_remind_user_ids
+#: model:ir.model.fields,field_description:intrastat_base.field_res_config_settings__intrastat_remind_user_ids
+msgid "Users Receiving the Intrastat Reminder"
+msgstr "Utilisateurs qui reçoivent le rappel DEB/DES"
+
+#~ msgid "Account Chart Template"
+#~ msgstr "Modèle de plan comptable"
+
+#~ msgid "Cannot delete the declaration %s because it is in Done state"
+#~ msgstr ""
+#~ "Impossible de supprimer la déclaration %s parce qu'elle est à l'état "
+#~ "'Terminé'."
+
+#~ msgid "Common functions for intrastat reports for products "
+#~ msgstr "Fonctions communes pour les rapports intrastat des produits "
+
+#~ msgid "Created by"
+#~ msgstr "Créé par"
+
+#~ msgid "Created on"
+#~ msgstr "Créé le"
+
+#~ msgid "Display Name"
+#~ msgstr "Afficher le nom"
+
+#~ msgid "ID"
+#~ msgstr "ID"
+
+#~ msgid "Intrastat Result View"
+#~ msgstr "Résultat DEB"
+
+#~ msgid "Is accessory cost"
+#~ msgstr "Est un frais accessoire"
+
+#~ msgid "Last Modified on"
+#~ msgstr "Dernière modification le"
+
+#~ msgid "Last Updated by"
+#~ msgstr "Dernière modification par"
+
+#~ msgid "Last Updated on"
+#~ msgstr "Dernière modification le"
+
+#~ msgid "Notes"
+#~ msgstr "Notes"
+
+#~ msgid "Ok"
+#~ msgstr "Ok"
+
+#~ msgid "Pop-up to show errors on intrastat report generation"
+#~ msgstr ""
+#~ "Pop-up qui affiche les erreurs lors de la génération du rapport intrastat"
+
+#~ msgid "The VAT number is not set for the partner '%s'."
+#~ msgstr "Numéro de TVA non renseigné sur le partenaire '%s'."
+
+#~ msgid ""
+#~ "The option 'Is accessory cost?' should only be activated on 'Service' "
+#~ "products. You have activated this option for the product '%s' which is of "
+#~ "type '%s'"
+#~ msgstr ""
+#~ "L'option 'Est un frais accessoire' ne doit être activée que sur des "
+#~ "articles de service. Vous avez activé cette option pour l'article '%s' "
+#~ "qui est de type '%s'"
+
+#~ msgid "Company not yet set on intrastat report."
+#~ msgstr "Société non configurée sur le rapport DEB/DES."
+
+#~ msgid "Country"
+#~ msgstr "Pays"
+
+#~ msgid "EU Country"
+#~ msgstr "Membre de l'UE"
+
+#~ msgid "Exclude invoice line from intrastat if this tax is present"
+#~ msgstr ""
+#~ "Ligne de facture exclue de la DEB et de la DES si cette taxe est présente"
+
+#~ msgid ""
+#~ "If this tax is present on an invoice line, this invoice line will be "
+#~ "skipped when generating Intrastat Product or Service lines from invoices."
+#~ msgstr ""
+#~ "Si cette taxe est présente sur une ligne de facture, cette ligne de "
+#~ "facture sera sautée lors de la génération de la DEB et de la DES à partir "
+#~ "des factures."
+
+#~ msgid "Intrastat Properties"
+#~ msgstr "Propriétés DEB/DES"
+
+#~ msgid "Search Countries"
+#~ msgstr "Recherche pays"
+
+#~ msgid "Set to True for all European Union countries."
+#~ msgstr "Cocher la case pour tous les pays de l'Union Européenne."
+
+#~ msgid "Tax"
+#~ msgstr "Taxe"
+
+#~ msgid "Templates for Taxes"
+#~ msgstr "Modèles pour les taxes"
+
+#~ msgid "The country is not set on the company '%s'."
+#~ msgstr "Pays non renseigné sur la société '%s'."
+
+#~ msgid "intrastat.result.view"
+#~ msgstr "intrastat.result.view"
+
+#~ msgid ""
+#~ "The generated XML file is not valid against the official XML Schema "
+#~ "Definition. The generated XML file and the full error have been written "
+#~ "in the server logs. Here is the error, which may give you an idea on the "
+#~ "cause of the problem : %s."
+#~ msgstr ""
+#~ "Le fichier XML n'est pas valide au regard du schéma de définition XML. Le "
+#~ "fichier XML généré et l'erreur complète ont été écrits dans les logs du "
+#~ "serveur Odoo. Voici l'erreur, qui pourrait vous aiguiller sur la cause du "
+#~ "problème : %s."
diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot
new file mode 100644
index 000000000..2db5f2df3
--- /dev/null
+++ b/intrastat_base/i18n/intrastat_base.pot
@@ -0,0 +1,155 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# 	* intrastat_base
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 15.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_product_product__is_accessory_cost
+#: model:ir.model.fields,help:intrastat_base.field_product_template__is_accessory_cost
+msgid ""
+"Activate this option for shipping costs, packaging costs and all services "
+"related to the sale of products. This option is used for Intrastat reports."
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_account_fiscal_position_template__intrastat
+msgid ""
+"Check this if you want to generate intrastat declarations withthe created "
+"fiscal position"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_config_settings
+msgid "Config Settings"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_res_partner
+msgid "Contact"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_fiscal_position
+msgid "Fiscal Position"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_account_fiscal_position__intrastat
+#: model:ir.model.fields,field_description:intrastat_base.field_account_fiscal_position_template__intrastat
+#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root
+#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_config_root
+#: model_terms:ir.ui.view,arch_db:intrastat_base.product_template_form_view
+#: model_terms:ir.ui.view,arch_db:intrastat_base.view_intrastat_res_config_settings
+msgid "Intrastat"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_account_bank_statement_line__intrastat_fiscal_position
+#: model:ir.model.fields,field_description:intrastat_base.field_account_move__intrastat_fiscal_position
+#: model:ir.model.fields,field_description:intrastat_base.field_account_payment__intrastat_fiscal_position
+msgid "Intrastat Fiscal Position"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_product_product__is_accessory_cost
+#: model:ir.model.fields,field_description:intrastat_base.field_product_template__is_accessory_cost
+msgid "Is Accessory Cost"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_move
+msgid "Journal Entry"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_res_company__intrastat_remind_user_ids
+#: model:ir.model.fields,help:intrastat_base.field_res_config_settings__intrastat_remind_user_ids
+msgid ""
+"List of Odoo users who will receive a notification to remind them about the "
+"Intrastat declaration."
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_res_company__intrastat_email_list
+msgid "List of emails of Users Receiving the Intrastat Reminder"
+msgstr ""
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_company.py:0
+#, python-format
+msgid "Missing e-mail address on user '%s'."
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_partner.py:0
+#, python-format
+msgid "Programming Error when calling '_get_intrastat_country_code()"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,help:intrastat_base.field_account_bank_statement_line__intrastat_fiscal_position
+#: model:ir.model.fields,help:intrastat_base.field_account_fiscal_position__intrastat
+#: model:ir.model.fields,help:intrastat_base.field_account_move__intrastat_fiscal_position
+#: model:ir.model.fields,help:intrastat_base.field_account_payment__intrastat_fiscal_position
+msgid ""
+"Set to True if the invoices with this fiscal position should be taken into "
+"account for the generation of the intrastat reports."
+msgstr ""
+
+#. module: intrastat_base
+#: model:product.product,name:intrastat_base.shipping_costs_exclude
+#: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template
+msgid "Shipping costs"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model,name:intrastat_base.model_account_fiscal_position_template
+msgid "Template for Fiscal Position"
+msgstr ""
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/product_template.py:0
+#, python-format
+msgid ""
+"The option 'Is accessory cost?' should only be activated on 'Service' "
+"products. You have activated this option for the product '{product_name}' "
+"which is configured with type '{product_type}'."
+msgstr ""
+
+#. module: intrastat_base
+#: model:product.product,uom_name:intrastat_base.shipping_costs_exclude
+#: model:product.template,uom_name:intrastat_base.shipping_costs_exclude_product_template
+msgid "Units"
+msgstr ""
+
+#. module: intrastat_base
+#: code:addons/intrastat_base/models/res_company.py:0
+#, python-format
+msgid "Unknown Error"
+msgstr ""
+
+#. module: intrastat_base
+#: model:ir.model.fields,field_description:intrastat_base.field_res_company__intrastat_remind_user_ids
+#: model:ir.model.fields,field_description:intrastat_base.field_res_config_settings__intrastat_remind_user_ids
+msgid "Users Receiving the Intrastat Reminder"
+msgstr ""
diff --git a/intrastat_base/models/__init__.py b/intrastat_base/models/__init__.py
new file mode 100644
index 000000000..cea19b9f8
--- /dev/null
+++ b/intrastat_base/models/__init__.py
@@ -0,0 +1,5 @@
+from . import product_template
+from . import res_company
+from . import account_fiscal_position
+from . import account_fiscal_position_template
+from . import account_move
diff --git a/intrastat_base/models/account_chart_template.py b/intrastat_base/models/account_chart_template.py
new file mode 100644
index 000000000..089941314
--- /dev/null
+++ b/intrastat_base/models/account_chart_template.py
@@ -0,0 +1,18 @@
+# Copyright 2020-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import models
+
+
+class AccountChartTemplate(models.Model):
+    _inherit = "account.chart.template"
+
+    def _get_fp_vals(self, company, position):
+        """
+        Get fiscal position chart template instrastat value
+        to create fiscal position
+        """
+        vals = super()._get_fp_vals(company, position)
+        vals["intrastat"] = position.intrastat
+        return vals
diff --git a/intrastat_base/models/account_fiscal_position.py b/intrastat_base/models/account_fiscal_position.py
new file mode 100644
index 000000000..f7d5ba8ee
--- /dev/null
+++ b/intrastat_base/models/account_fiscal_position.py
@@ -0,0 +1,51 @@
+# Copyright 2020-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
+
+
+class AccountFiscalPosition(models.Model):
+    _inherit = "account.fiscal.position"
+
+    intrastat = fields.Selection(
+        "_intrastat_selection",
+        help="When set to B2B or B2C, the invoices with this fiscal position will "
+        "be taken into account for the generation of the intrastat reports.",
+    )
+
+    @api.model
+    def _intrastat_selection(self):
+        return [
+            ("b2b", _("B2B")),
+            ("b2c", _("B2C")),
+            ("no", _("No")),
+        ]
+
+    @api.constrains("intrastat", "vat_required")
+    def _check_intrastat(self):
+        for position in self:
+            if position.intrastat == "b2b" and not position.vat_required:
+                raise ValidationError(
+                    _(
+                        "The fiscal position '%s' has intrastat set to B2B, "
+                        "so the option 'VAT Required' must be enabled."
+                    )
+                    % position.display_name
+                )
+            elif position.intrastat == "b2c" and position.vat_required:
+                raise ValidationError(
+                    _(
+                        "The fiscal position '%s' has intrastat set to B2C, "
+                        "so the option 'VAT Required' mustn't be enabled."
+                    )
+                    % position.display_name
+                )
+
+    @api.onchange("intrastat", "vat_required")
+    def intrastat_change(self):
+        if self.intrastat == "b2b" and not self.vat_required:
+            self.vat_required = True
+        elif self.intrastat == "b2c" and self.vat_required:
+            self.vat_required = False
diff --git a/intrastat_base/models/account_fiscal_position_template.py b/intrastat_base/models/account_fiscal_position_template.py
new file mode 100644
index 000000000..e4dd231ef
--- /dev/null
+++ b/intrastat_base/models/account_fiscal_position_template.py
@@ -0,0 +1,18 @@
+# Copyright 2020-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo import api, fields, models
+
+
+class AccountFiscalPositionTemplate(models.Model):
+    _inherit = "account.fiscal.position.template"
+
+    intrastat = fields.Selection(
+        "_intrastat_selection",
+        help="When set to B2B or B2C, the invoices with this fiscal position will "
+        "be taken into account for the generation of the intrastat reports.",
+    )
+
+    @api.model
+    def _intrastat_selection(self):
+        return self.env["account.fiscal.position"]._intrastat_selection()
diff --git a/intrastat_base/models/account_move.py b/intrastat_base/models/account_move.py
new file mode 100644
index 000000000..8ef526992
--- /dev/null
+++ b/intrastat_base/models/account_move.py
@@ -0,0 +1,15 @@
+# Copyright 2020-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class AccountMove(models.Model):
+    _inherit = "account.move"
+
+    intrastat_fiscal_position = fields.Selection(
+        related="fiscal_position_id.intrastat",
+        store=True,
+        string="Intrastat Fiscal Position",
+    )
diff --git a/intrastat_base/models/product_template.py b/intrastat_base/models/product_template.py
new file mode 100644
index 000000000..b8da8d2ad
--- /dev/null
+++ b/intrastat_base/models/product_template.py
@@ -0,0 +1,34 @@
+# Copyright 2010-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
+
+
+class ProductTemplate(models.Model):
+    _inherit = "product.template"
+
+    is_accessory_cost = fields.Boolean(
+        help="Activate this option for shipping costs, packaging "
+        "costs and all services related to the sale of products. "
+        "This option is used for Intrastat reports.",
+    )
+
+    @api.constrains("type", "is_accessory_cost")
+    def _check_accessory_cost(self):
+        for this in self:
+            if this.is_accessory_cost and this.type != "service":
+                raise ValidationError(
+                    _(
+                        "The option 'Is accessory cost?' should only be "
+                        "activated on 'Service' products. You have activated "
+                        "this option for the product '{product_name}' which is "
+                        "configured with type '{product_type}'."
+                    ).format(
+                        product_name=this.display_name,
+                        product_type=this._fields["type"].convert_to_export(
+                            this.type, this
+                        ),
+                    )
+                )
diff --git a/intrastat_base/models/res_company.py b/intrastat_base/models/res_company.py
new file mode 100644
index 000000000..71989949e
--- /dev/null
+++ b/intrastat_base/models/res_company.py
@@ -0,0 +1,72 @@
+# Copyright 2013-2022 Akretion France (http://www.akretion.com/)
+# @author: <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from io import BytesIO
+from sys import exc_info
+from traceback import format_exception
+
+from lxml import etree
+
+from odoo import _, api, fields, models, tools
+from odoo.exceptions import UserError, ValidationError
+
+logger = logging.getLogger(__name__)
+
+
+class ResCompany(models.Model):
+    _inherit = "res.company"
+
+    intrastat_remind_user_ids = fields.Many2many(
+        comodel_name="res.users",
+        relation="company_intrastat_reminder_user_rel",
+        column1="company_id",
+        column2="user_id",
+        string="Users Receiving the Intrastat Reminder",
+        help="List of Odoo users who will receive a notification to "
+        "remind them about the Intrastat declaration.",
+    )
+    intrastat_email_list = fields.Char(
+        compute="_compute_intrastat_email_list",
+        string="List of emails of Users Receiving the Intrastat Reminder",
+    )
+
+    @api.depends("intrastat_remind_user_ids", "intrastat_remind_user_ids.email")
+    def _compute_intrastat_email_list(self):
+        for this in self:
+            emails = []
+            for user in this.intrastat_remind_user_ids:
+                if user.email:
+                    emails.append(user.email)
+            this.intrastat_email_list = ",".join(emails)
+
+    @api.constrains("intrastat_remind_user_ids")
+    def _check_intrastat_remind_users(self):
+        for this in self:
+            for user in this.intrastat_remind_user_ids:
+                if not user.email:
+                    raise ValidationError(
+                        _("Missing e-mail address on user '%s'.") % (user.name)
+                    )
+
+    @api.model
+    def _intrastat_check_xml_schema(self, xml_bytes, xsd_file):
+        """Validate the XML file against the XSD"""
+        xsd_etree_obj = etree.parse(tools.file_open(xsd_file, mode="rb"))
+        official_schema = etree.XMLSchema(xsd_etree_obj)
+        try:
+            t = etree.parse(BytesIO(xml_bytes))
+            official_schema.assertValid(t)
+        except (etree.XMLSchemaParseError, etree.DocumentInvalid) as e:
+            logger.warning("The XML file is invalid against the XML Schema Definition")
+            logger.warning(xml_bytes)
+            logger.warning(e)
+            usererror = "{}\n\n{}".format(e.__class__.__name__, str(e))
+            raise UserError(usererror) from e
+        except Exception as e:
+            error = _("Unknown Error")
+            tb = "".join(format_exception(*exc_info()))
+            error += "\n%s" % tb
+            logger.warning(error)
+            raise UserError(error) from e
diff --git a/intrastat_base/readme/CONTRIBUTORS.rst b/intrastat_base/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000..af9ef5225
--- /dev/null
+++ b/intrastat_base/readme/CONTRIBUTORS.rst
@@ -0,0 +1,5 @@
+* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
+* Luc De Meyer, Noviat <info@noviat.com>
+* Kumar Aberer, brain-tec AG <kumar.aberer@braintec-group.com>
+* Andrea Stirpe <a.stirpe@onestein.nl>
+* Denis Roussel <denis.roussel@acsone.eu>
diff --git a/intrastat_base/readme/DESCRIPTION.rst b/intrastat_base/readme/DESCRIPTION.rst
new file mode 100644
index 000000000..179c7eb18
--- /dev/null
+++ b/intrastat_base/readme/DESCRIPTION.rst
@@ -0,0 +1,11 @@
+This module contains common functions for the intrastat reporting and
+should be used in combination with the generic reporting module
+*intrastat_product* and with the country-specific reporting modules such
+as:
+
+- *l10n_fr_intrastat_service*:
+  the module for the *Déclaration Européenne des Services* (DES) for France
+- *l10n_fr_intrastat_product*:
+  the module for the *Déclaration d'Echange de Biens* (DEB) for France
+- *l10n_be_intrastat_product*:
+  the module for the Intrastat Declaration for Belgium.
diff --git a/intrastat_base/readme/INSTALL.rst b/intrastat_base/readme/INSTALL.rst
new file mode 100644
index 000000000..2f4f69f25
--- /dev/null
+++ b/intrastat_base/readme/INSTALL.rst
@@ -0,0 +1,5 @@
+WARNING:
+
+This module conflicts with the module *account_intrastat* from Odoo Enterprise.
+If you have already installed the module *account_intrastat*,
+you should uninstall it first before installing this module.
diff --git a/intrastat_base/readme/USAGE.rst b/intrastat_base/readme/USAGE.rst
new file mode 100644
index 000000000..7f7a6d0ad
--- /dev/null
+++ b/intrastat_base/readme/USAGE.rst
@@ -0,0 +1,5 @@
+This module adds an intrastat property on fiscal positions.
+
+With this module, the country field on partners becomes a required field.
+
+It adds an *Intrastat* section on the *Invoicing* configuration page.
diff --git a/intrastat_base/static/description/icon.png b/intrastat_base/static/description/icon.png
new file mode 100644
index 000000000..3a0328b51
Binary files /dev/null and b/intrastat_base/static/description/icon.png differ
diff --git a/intrastat_base/static/description/index.html b/intrastat_base/static/description/index.html
new file mode 100644
index 000000000..afc4c9a70
--- /dev/null
+++ b/intrastat_base/static/description/index.html
@@ -0,0 +1,453 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
+<title>Intrastat Reporting Base</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+.subscript {
+  vertical-align: sub;
+  font-size: smaller }
+
+.superscript {
+  vertical-align: super;
+  font-size: smaller }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+  overflow: hidden;
+}
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title, .code .error {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left, .figure.align-left, object.align-left, table.align-left {
+  clear: left ;
+  float: left ;
+  margin-right: 1em }
+
+img.align-right, .figure.align-right, object.align-right, table.align-right {
+  clear: right ;
+  float: right ;
+  margin-left: 1em }
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+table.align-center {
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+  text-align: left }
+
+.align-center {
+  clear: both ;
+  text-align: center }
+
+.align-right {
+  text-align: right }
+
+/* reset inner alignment in figures */
+div.align-right {
+  text-align: inherit }
+
+/* div.align-center * { */
+/*   text-align: left } */
+
+.align-top    {
+  vertical-align: top }
+
+.align-middle {
+  vertical-align: middle }
+
+.align-bottom {
+  vertical-align: bottom }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font: inherit }
+
+pre.literal-block, pre.doctest-block, pre.math, pre.code {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+pre.code .ln { color: grey; } /* line numbers */
+pre.code, code { background-color: #eeeeee }
+pre.code .comment, code .comment { color: #5C6576 }
+pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
+pre.code .literal.string, code .literal.string { color: #0C5404 }
+pre.code .name.builtin, code .name.builtin { color: #352B84 }
+pre.code .deleted, code .deleted { background-color: #DEB0A1}
+pre.code .inserted, code .inserted { background-color: #A3D289}
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+/* "booktabs" style (no vertical lines) */
+table.docutils.booktabs {
+  border: 0px;
+  border-top: 2px solid;
+  border-bottom: 2px solid;
+  border-collapse: collapse;
+}
+table.docutils.booktabs * {
+  border: 0px;
+}
+table.docutils.booktabs th {
+  border-bottom: thin solid;
+  text-align: left;
+}
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+ul.auto-toc {
+  list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="intrastat-reporting-base">
+<h1 class="title">Intrastat Reporting Base</h1>
+
+<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!! This file is generated by oca-gen-addon-readme !!
+!! changes will be overwritten.                   !!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
+<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/tree/15.0/intrastat_base"><img alt="OCA/intrastat-extrastat" src="https://img.shields.io/badge/github-OCA%2Fintrastat--extrastat-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/intrastat-extrastat-15-0/intrastat-extrastat-15-0-intrastat_base"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/227/15.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
+<p>This module contains common functions for the intrastat reporting and
+should be used in combination with the generic reporting module
+<em>intrastat_product</em> and with the country-specific reporting modules such
+as:</p>
+<ul class="simple">
+<li><em>l10n_fr_intrastat_service</em>:
+the module for the <em>Déclaration Européenne des Services</em> (DES) for France</li>
+<li><em>l10n_fr_intrastat_product</em>:
+the module for the <em>Déclaration d’Echange de Biens</em> (DEB) for France</li>
+<li><em>l10n_be_intrastat_product</em>:
+the module for the Intrastat Declaration for Belgium.</li>
+</ul>
+<p><strong>Table of contents</strong></p>
+<div class="contents local topic" id="contents">
+<ul class="simple">
+<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
+<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
+<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
+<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
+<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
+<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
+<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="installation">
+<h1><a class="toc-backref" href="#id1">Installation</a></h1>
+<p>WARNING:</p>
+<p>This module conflicts with the module <em>account_intrastat</em> from Odoo Enterprise.
+If you have already installed the module <em>account_intrastat</em>,
+you should uninstall it first before installing this module.</p>
+</div>
+<div class="section" id="usage">
+<h1><a class="toc-backref" href="#id2">Usage</a></h1>
+<p>This module adds an intrastat property on fiscal positions.</p>
+<p>With this module, the country field on partners becomes a required field.</p>
+<p>It adds an <em>Intrastat</em> section on the <em>Invoicing</em> configuration page.</p>
+</div>
+<div class="section" id="bug-tracker">
+<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
+<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/issues">GitHub Issues</a>.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+<a class="reference external" href="https://github.com/OCA/intrastat-extrastat/issues/new?body=module:%20intrastat_base%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
+<p>Do not contact contributors directly about support or help with technical issues.</p>
+</div>
+<div class="section" id="credits">
+<h1><a class="toc-backref" href="#id4">Credits</a></h1>
+<div class="section" id="authors">
+<h2><a class="toc-backref" href="#id5">Authors</a></h2>
+<ul class="simple">
+<li>ACSONE SA/NV</li>
+<li>Akretion</li>
+<li>Noviat</li>
+</ul>
+</div>
+<div class="section" id="contributors">
+<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
+<ul class="simple">
+<li>Alexis de Lattre, Akretion &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
+<li>Luc De Meyer, Noviat &lt;<a class="reference external" href="mailto:info&#64;noviat.com">info&#64;noviat.com</a>&gt;</li>
+<li>Kumar Aberer, brain-tec AG &lt;<a class="reference external" href="mailto:kumar.aberer&#64;braintec-group.com">kumar.aberer&#64;braintec-group.com</a>&gt;</li>
+<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</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>
+</ul>
+</div>
+<div class="section" id="maintainers">
+<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
+<p>This module is maintained by the OCA.</p>
+<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
+<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.</p>
+<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
+<p><a class="reference external" href="https://github.com/alexis-via"><img alt="alexis-via" src="https://github.com/alexis-via.png?size=40px" /></a> <a class="reference external" href="https://github.com/luc-demeyer"><img alt="luc-demeyer" src="https://github.com/luc-demeyer.png?size=40px" /></a></p>
+<p>This module is part of the <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/tree/15.0/intrastat_base">OCA/intrastat-extrastat</a> project on GitHub.</p>
+<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
+</div>
+</div>
+</div>
+</body>
+</html>
diff --git a/intrastat_base/views/account_fiscal_position.xml b/intrastat_base/views/account_fiscal_position.xml
new file mode 100644
index 000000000..7c7dbfbb8
--- /dev/null
+++ b/intrastat_base/views/account_fiscal_position.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2020-2022 Akretion France (https://akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <record id="view_account_position_form" model="ir.ui.view">
+        <field name="name">intrastat.account.fiscal.position.form</field>
+        <field name="model">account.fiscal.position</field>
+        <field name="inherit_id" ref="account.view_account_position_form" />
+        <field name="arch" type="xml">
+            <field name="vat_required" position="after">
+                <field name="intrastat" />
+            </field>
+        </field>
+    </record>
+    <record id="view_account_position_tree" model="ir.ui.view">
+        <field name="name">intrastat.account.fiscal.position.tree</field>
+        <field name="model">account.fiscal.position</field>
+        <field name="inherit_id" ref="account.view_account_position_tree" />
+        <field name="arch" type="xml">
+            <field name="name" position="after">
+                <field name="intrastat" optional="show" />
+            </field>
+        </field>
+    </record>
+    <record id="view_account_position_filter" model="ir.ui.view">
+        <field name="model">account.fiscal.position</field>
+        <field name="inherit_id" ref="account.view_account_position_filter" />
+        <field name="arch" type="xml">
+            <field name="name" position="after">
+                <filter
+                    name="intrastat"
+                    domain="[('intrastat', 'in', ('b2b', 'b2c'))]"
+                    string="Intrastat"
+                />
+                <separator />
+            </field>
+            <filter name="active" position="after">
+                <group name="groupby">
+                    <filter
+                        name="intrastat_groupby"
+                        string="Intrastat"
+                        context="{'group_by': 'intrastat'}"
+                    />
+                </group>
+            </filter>
+        </field>
+    </record>
+</odoo>
diff --git a/intrastat_base/views/account_fiscal_position_template.xml b/intrastat_base/views/account_fiscal_position_template.xml
new file mode 100644
index 000000000..b05a839b6
--- /dev/null
+++ b/intrastat_base/views/account_fiscal_position_template.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2023 Akretion France (https://akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <record id="view_account_position_template_form" model="ir.ui.view">
+        <field name="name">intrastat.account.fiscal.position.form</field>
+        <field name="model">account.fiscal.position.template</field>
+        <field name="inherit_id" ref="account.view_account_position_template_form" />
+        <field name="arch" type="xml">
+            <field name="name" position="after">
+                <field name="intrastat" />
+            </field>
+        </field>
+    </record>
+    <record id="view_account_position_template_tree" model="ir.ui.view">
+        <field name="name">intrastat.account.fiscal.position.tree</field>
+        <field name="model">account.fiscal.position.template</field>
+        <field name="inherit_id" ref="account.view_account_position_template_tree" />
+        <field name="arch" type="xml">
+            <field name="name" position="after">
+                <field name="intrastat" optional="show" />
+            </field>
+        </field>
+    </record>
+    <record id="view_account_position_template_search" model="ir.ui.view">
+        <field name="model">account.fiscal.position.template</field>
+        <field name="inherit_id" ref="account.view_account_position_template_search" />
+        <field name="arch" type="xml">
+            <field name="name" position="after">
+                <filter
+                    name="intrastat"
+                    domain="[('intrastat', 'in', ('b2b', 'b2c'))]"
+                    string="Intrastat"
+                />
+                <group name="groupby">
+                    <filter
+                        name="intrastat_groupby"
+                        string="Intrastat"
+                        context="{'group_by': 'intrastat'}"
+                    />
+                </group>
+            </field>
+        </field>
+    </record>
+</odoo>
diff --git a/intrastat_base/views/intrastat.xml b/intrastat_base/views/intrastat.xml
new file mode 100644
index 000000000..8469cd7ca
--- /dev/null
+++ b/intrastat_base/views/intrastat.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2011-2022 Akretion France (http://www.akretion.com/)
+  Copyright 2015-2022 Noviat (http://www.noviat.com/)
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <!-- Menu entries for Intrastat -->
+    <menuitem
+        id="menu_intrastat_base_root"
+        name="Intrastat"
+        parent="account.menu_finance_reports"
+        sequence="50"
+    />
+    <menuitem
+        id="menu_intrastat_config_root"
+        name="Intrastat"
+        parent="account.menu_finance_configuration"
+        sequence="50"
+    />
+</odoo>
diff --git a/intrastat_base/views/product_template.xml b/intrastat_base/views/product_template.xml
new file mode 100644
index 000000000..93961c5d2
--- /dev/null
+++ b/intrastat_base/views/product_template.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2010-2022 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <record id="product_template_form_view" model="ir.ui.view">
+        <field name="name">intrastat.base.product.template.form</field>
+        <field name="model">product.template</field>
+        <field name="inherit_id" ref="account.product_template_form_view" />
+        <field name="arch" type="xml">
+            <group name="properties" position="after">
+                <group string="Intrastat" name="intrastat">
+                    <!-- If you need this field, inherit this view in a
+                         localisation module to set invisible="0" -->
+                    <field
+                        name="is_accessory_cost"
+                        attrs="{'invisible': [('type', '!=', 'service')]}"
+                        invisible="1"
+                    />
+                </group>
+            </group>
+        </field>
+    </record>
+</odoo>
diff --git a/intrastat_base/views/res_config_settings.xml b/intrastat_base/views/res_config_settings.xml
new file mode 100644
index 000000000..2c82cd9e7
--- /dev/null
+++ b/intrastat_base/views/res_config_settings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2013-2022 Akretion France (http://www.akretion.com/)
+  @author: Alexis de Lattre <alexis.delattre@akretion.com>
+  Copyright 2018-2022 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <record id="view_intrastat_res_config_settings" model="ir.ui.view">
+        <field name="name">intrastat.res.config.settings.form</field>
+        <field name="model">res.config.settings</field>
+        <field name="inherit_id" ref="account.res_config_settings_view_form" />
+        <field name="arch" type="xml">
+            <xpath expr="//div[@id='storno']" position="after">
+                <h2>Intrastat</h2>
+                <div class="row mt16 o_settings_container" id="intrastat">
+                    <div class="col-12 col-lg-12 o_setting_box" id="intrastat-settings">
+                        <div class="o_setting_left_pane" />
+                        <div class="o_setting_right_pane">
+                            <div class="row">
+                                <label
+                                    for="intrastat_remind_user_ids"
+                                    class="col-md-5"
+                                />
+                                <field
+                                    name="intrastat_remind_user_ids"
+                                    widget="many2many_tags"
+                                />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </xpath>
+        </field>
+    </record>
+</odoo>
diff --git a/intrastat_base/views/res_partner.xml b/intrastat_base/views/res_partner.xml
new file mode 100644
index 000000000..3fc4d2e1f
--- /dev/null
+++ b/intrastat_base/views/res_partner.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  Copyright 2010-2022 Akretion France (http://www.akretion.com/)
+  @author David BEAL <david.beal@akretion.com>
+  License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+-->
+<odoo>
+    <!-- Set country_id field to required on partner form view -->
+    <record id="view_partner_form" model="ir.ui.view">
+        <field name="model">res.partner</field>
+        <field name="inherit_id" ref="base.view_partner_form" />
+        <field name="arch" type="xml">
+            <xpath expr="//field[@name='country_id']" position="attributes">
+                <attribute name="required">1</attribute>
+            </xpath>
+            <xpath
+                expr="//field[@name='child_ids']/form//field[@name='country_id']"
+                position="attributes"
+            >
+                <attribute name="required">1</attribute>
+            </xpath>
+        </field>
+    </record>
+</odoo>
diff --git a/intrastat_base/wizards/__init__.py b/intrastat_base/wizards/__init__.py
new file mode 100644
index 000000000..0deb68c46
--- /dev/null
+++ b/intrastat_base/wizards/__init__.py
@@ -0,0 +1,1 @@
+from . import res_config_settings
diff --git a/intrastat_base/wizards/res_config_settings.py b/intrastat_base/wizards/res_config_settings.py
new file mode 100644
index 000000000..9806cb437
--- /dev/null
+++ b/intrastat_base/wizards/res_config_settings.py
@@ -0,0 +1,14 @@
+# Copyright 2017-2022 Akretion France (http://www.akretion.com/)
+# Copyright 2018-2022 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
+# @author: Alexis de Lattre <alexis.delattre@akretion.com>
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+    _inherit = "res.config.settings"
+
+    intrastat_remind_user_ids = fields.Many2many(
+        related="company_id.intrastat_remind_user_ids", readonly=False
+    )
diff --git a/setup/intrastat_base/odoo/addons/intrastat_base b/setup/intrastat_base/odoo/addons/intrastat_base
new file mode 120000
index 000000000..74df3f8a6
--- /dev/null
+++ b/setup/intrastat_base/odoo/addons/intrastat_base
@@ -0,0 +1,1 @@
+../../../../intrastat_base
\ No newline at end of file
diff --git a/setup/intrastat_base/setup.py b/setup/intrastat_base/setup.py
new file mode 100644
index 000000000..28c57bb64
--- /dev/null
+++ b/setup/intrastat_base/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+    setup_requires=['setuptools-odoo'],
+    odoo_addon=True,
+)


Test patch:
diff --git a/intrastat_base/tests/__init__.py b/intrastat_base/tests/__init__.py
new file mode 100644
index 000000000..a2afb4b92
--- /dev/null
+++ b/intrastat_base/tests/__init__.py
@@ -0,0 +1,2 @@
+from . import common
+from . import test_all
diff --git a/intrastat_base/tests/common.py b/intrastat_base/tests/common.py
new file mode 100644
index 000000000..ac1fbf309
--- /dev/null
+++ b/intrastat_base/tests/common.py
@@ -0,0 +1,16 @@
+# Copyright 2021 ACSONE SA/NV
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+class IntrastatCommon(object):
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass()
+        cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
+        cls.chart_template_obj = cls.env["account.chart.template"]
+        cls.mail_obj = cls.env["mail.mail"]
+
+        cls.demo_user = cls.env.ref("base.user_demo")
+        cls.demo_company = cls.env.ref("base.main_company")
+
+        cls.shipping_cost = cls.env.ref("intrastat_base.shipping_costs_exclude")
diff --git a/intrastat_base/tests/models.py b/intrastat_base/tests/models.py
new file mode 100644
index 000000000..302914c6f
--- /dev/null
+++ b/intrastat_base/tests/models.py
@@ -0,0 +1,10 @@
+# Copyright 2021 ACSONE SA/NV
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import models
+
+
+class IntrastatDeclarationTest(models.Model):
+    _inherit = ["mail.thread", "mail.activity.mixin", "intrastat.common"]
+    _name = "intrastat.declaration.test"
+    _description = "Intrastat Declaration Test"
diff --git a/intrastat_base/tests/test_all.py b/intrastat_base/tests/test_all.py
new file mode 100644
index 000000000..70913a600
--- /dev/null
+++ b/intrastat_base/tests/test_all.py
@@ -0,0 +1,48 @@
+from odoo.exceptions import ValidationError
+
+from .common import IntrastatCommon
+
+
+class TestIntrastatBase(IntrastatCommon):
+    """Tests for this module"""
+
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass()
+
+    def test_company(self):
+        # add 'Demo user' to intrastat_remind_user_ids
+        self.demo_company.write(
+            {"intrastat_remind_user_ids": [(6, False, [self.demo_user.id])]}
+        )
+        # then check if intrastat_email_list contains the email of the user
+        self.assertEqual(self.demo_company.intrastat_email_list, self.demo_user.email)
+
+    def test_no_email(self):
+        self.demo_user.email = False
+        with self.assertRaises(ValidationError):
+            self.demo_company.write(
+                {"intrastat_remind_user_ids": [(6, False, [self.demo_user.id])]}
+            )
+
+    def test_accessory(self):
+        with self.assertRaises(ValidationError):
+            self.shipping_cost.type = "consu"
+
+    def test_fiscal_position(self):
+        with self.assertRaises(ValidationError):
+            self.env["account.fiscal.position"].create(
+                {
+                    "name": "TestB2B",
+                    "vat_required": False,
+                    "intrastat": "b2b",
+                }
+            )
+        with self.assertRaises(ValidationError):
+            self.env["account.fiscal.position"].create(
+                {
+                    "name": "TestB2C",
+                    "vat_required": True,
+                    "intrastat": "b2c",
+                }
+            )