diff --git a/l10n_fr_cog/README.rst b/l10n_fr_cog/README.rst new file mode 100644 index 0000000000..e0a131dca5 --- /dev/null +++ b/l10n_fr_cog/README.rst @@ -0,0 +1,83 @@ +========================== +Code Officiel Géographique +========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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%2Fl10n--france-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-france/tree/14.0/l10n_fr_cog + :alt: OCA/l10n-france +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-france-14-0/l10n-france-14-0-l10n_fr_cog + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/121/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds the *Code Officiel Géographique* of `INSEE `_ on countries. All countries except France and DOM-TOMs (and some very particular territories) have this code. + +This module is used by other modules of the French localization such as the DAS2 module. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Alexis de Lattre + +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 + +Current `maintainer `__: + +|maintainer-alexis-via| + +This module is part of the `OCA/l10n-france `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_fr_cog/__init__.py b/l10n_fr_cog/__init__.py new file mode 100644 index 0000000000..65d052762b --- /dev/null +++ b/l10n_fr_cog/__init__.py @@ -0,0 +1,2 @@ +from .post_install import set_fr_cog +from . import models diff --git a/l10n_fr_cog/__manifest__.py b/l10n_fr_cog/__manifest__.py new file mode 100644 index 0000000000..404170f34c --- /dev/null +++ b/l10n_fr_cog/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2020-2023 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Code Officiel Géographique", + "summary": "Add Code Officiel Géographique (COG) on countries", + "version": "15.0.1.0.0", + "category": "French Localization", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/l10n-france", + "license": "AGPL-3", + "depends": ["base"], + "data": [ + "data/country.xml", + "views/country.xml", + ], + "post_init_hook": "set_fr_cog", + "installable": True, +} diff --git a/l10n_fr_cog/data/country.xml b/l10n_fr_cog/data/country.xml new file mode 100644 index 0000000000..239d031e1b --- /dev/null +++ b/l10n_fr_cog/data/country.xml @@ -0,0 +1,947 @@ + + + + + + + 99130 + + + + 99247 + + + + 99212 + + + + 99441 + + + + 99425 + + + + 99125 + + + + 99252 + + + + 99395 + + + + 99415 + + + + 99505 + + + + 99110 + + + + 99501 + + + + 99135 + + + + 99253 + + + + 99118 + + + + 99434 + + + + 99246 + + + + 99131 + + + + 99331 + + + + 99111 + + + + 99249 + + + + 99321 + + + + 99327 + + + + 99425 + + + + 99225 + + + + 99418 + + + + 99443 + + + + 99416 + + + + 99436 + + + + 99214 + + + + 99103 + + + + 99347 + + + + 99148 + + + + 99429 + + + + 99401 + + + + 99501 + + + + 99323 + + + + 99312 + + + + 99324 + + + + 99140 + + + + 99326 + + + + 99502 + + + + 99417 + + + + 99322 + + + + 99216 + + + + 99419 + + + + 99406 + + + + 99407 + + + + 99396 + + + + 99444 + + + + 99501 + + + + 99254 + + + + 99116 + + + + 99109 + + + + 99399 + + + + 99101 + + + + 99438 + + + + 99408 + + + + 99352 + + + + 99420 + + + + 99106 + + + + 99301 + + + + 99389 + + + + 99317 + + + + 99134 + + + + 99315 + + + + 99105 + + + + 99508 + + + + 99427 + + + + 99516 + + + + 99101 + + + + 99328 + + + + 99435 + + + + 99255 + + + + 99329 + + + + 99133 + + + + 99132 + + + + 99430 + + + + 99304 + + + + 99330 + + + + 99314 + + + + 99126 + + + + 99427 + + + + 99409 + + + + 99505 + + + + 99392 + + + + 99428 + + + + 99230 + + + + 99501 + + + + 99411 + + + + 99119 + + + + 99410 + + + + 99112 + + + + 99231 + + + + 99136 + + + + 99207 + + + + 99132 + + + + 99223 + + + + 99308 + + + + 99203 + + + + 99204 + + + + 99102 + + + + 99127 + + + + 99132 + + + + 99426 + + + + 99222 + + + + 99217 + + + + 99332 + + + + 99257 + + + + 99234 + + + + 99513 + + + + 99397 + + + + 99442 + + + + 99238 + + + + 99239 + + + + 99240 + + + + 99425 + + + + 99256 + + + + 99241 + + + + 99205 + + + + 99439 + + + + 99113 + + + + 99235 + + + + 99302 + + + + 99348 + + + + 99108 + + + + 99137 + + + + 99107 + + + + 99316 + + + + 99350 + + + + 99138 + + + + 99151 + + + + 99120 + + + + 99333 + + + + 99515 + + + + 99156 + + + + 99335 + + + + 99224 + + + + 99242 + + + + 99232 + + + + 99505 + + + + 99336 + + + + 99425 + + + + 99144 + + + + 99390 + + + + 99229 + + + + 99334 + + + + 99405 + + + + 99227 + + + + 99393 + + + + 99311 + + + + 99337 + + + + 99501 + + + + 99338 + + + + 99412 + + + + 99135 + + + + 99103 + + + + 99215 + + + + 99507 + + + + 99502 + + + + 99502 + + + + 99250 + + + + 99413 + + + + 99422 + + + + 99510 + + + + 99220 + + + + 99213 + + + + 99122 + + + + 99503 + + + + 99432 + + + + 99261 + + + + 99139 + + + + 99517 + + + + 99421 + + + + 99248 + + + + 99114 + + + + 99121 + + + + 99123 + + + + 99340 + + + + 99201 + + + + 99512 + + + + 99398 + + + + 99343 + + + + 99104 + + + + 99226 + + + + 99306 + + + + 99145 + + + + 99103 + + + + 99117 + + + + 99342 + + + + 99128 + + + + 99341 + + + + 99318 + + + + 99437 + + + + 99349 + + + + 99394 + + + + 99414 + + + + 99445 + + + + 99206 + + + + 99391 + + + + 99425 + + + + 99344 + + + + 99345 + + + + 99219 + + + + 99259 + + + + 99502 + + + + 99262 + + + + 99260 + + + + 99351 + + + + 99509 + + + + 99208 + + + + 99433 + + + + 99511 + + + + 99236 + + + + 99309 + + + + 99155 + + + + 99339 + + + + 99132 + + + + 99404 + + + + 99423 + + + + 99258 + + + + 99129 + + + + 99440 + + + + 99424 + + + + 99425 + + + + 99432 + + + + 99243 + + + + 99514 + + + + 99506 + + + + 99251 + + + + 99303 + + + + 99346 + + + + 99310 + + + + 99157 + + + + diff --git a/l10n_fr_cog/i18n/l10n_fr_cog.pot b/l10n_fr_cog/i18n/l10n_fr_cog.pot new file mode 100644 index 0000000000..9de15fc110 --- /dev/null +++ b/l10n_fr_cog/i18n/l10n_fr_cog.pot @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_fr_cog +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.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: l10n_fr_cog +#: model:ir.model.fields,field_description:l10n_fr_cog.field_res_country__fr_cog +msgid "Code Officiel Géographique" +msgstr "" + +#. module: l10n_fr_cog +#: model:ir.model.fields,help:l10n_fr_cog.field_res_country__fr_cog +msgid "Code Officiel Géographique, by INSEE" +msgstr "" + +#. module: l10n_fr_cog +#: model:ir.model,name:l10n_fr_cog.model_res_country +msgid "Country" +msgstr "" + +#. module: l10n_fr_cog +#: model:ir.model.fields,field_description:l10n_fr_cog.field_res_country__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_fr_cog +#: model:ir.model.fields,field_description:l10n_fr_cog.field_res_country__id +msgid "ID" +msgstr "" + +#. module: l10n_fr_cog +#: model:ir.model.fields,field_description:l10n_fr_cog.field_res_country____last_update +msgid "Last Modified on" +msgstr "" diff --git a/l10n_fr_cog/models/__init__.py b/l10n_fr_cog/models/__init__.py new file mode 100644 index 0000000000..11573766f2 --- /dev/null +++ b/l10n_fr_cog/models/__init__.py @@ -0,0 +1 @@ +from . import res_country diff --git a/l10n_fr_cog/models/res_country.py b/l10n_fr_cog/models/res_country.py new file mode 100644 index 0000000000..3bc1e50698 --- /dev/null +++ b/l10n_fr_cog/models/res_country.py @@ -0,0 +1,13 @@ +# Copyright 2020-2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCountry(models.Model): + _inherit = "res.country" + + fr_cog = fields.Integer( + string="Code Officiel Géographique", help="Code Officiel Géographique, by INSEE" + ) diff --git a/l10n_fr_cog/post_install.py b/l10n_fr_cog/post_install.py new file mode 100644 index 0000000000..bcc5346390 --- /dev/null +++ b/l10n_fr_cog/post_install.py @@ -0,0 +1,38 @@ +# Copyright 2020 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +from lxml import etree + +from odoo import SUPERUSER_ID, api +from odoo.tools import file_open + +logger = logging.getLogger(__name__) + + +# Countries data is provided in the base module with noupdate="1" +# That's why we need this post-install script +def set_fr_cog(cr, registry): + f = file_open("l10n_fr_cog/data/country.xml", "rb") + xml_root = etree.parse(f) + data = {} + for record in xml_root.xpath("//record"): + xmlid = record.attrib["id"] + data[xmlid] = {} + for xfield in record.xpath("field"): + if xfield.attrib and xfield.attrib.get("name") == "fr_cog": + data[xmlid] = int(xfield.text) + logger.debug("set_fr_cog data=%s", data) + env = api.Environment(cr, SUPERUSER_ID, {}) + for xmlid, fr_cog in data.items(): + country = env.ref(xmlid) + country.fr_cog = fr_cog + logger.debug( + "Country ID %d xmlid %s updated with fr_cog=%d", + country.id, + xmlid, + fr_cog, + ) + return diff --git a/l10n_fr_cog/readme/CONTRIBUTORS.rst b/l10n_fr_cog/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..ff65d68ce6 --- /dev/null +++ b/l10n_fr_cog/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/l10n_fr_cog/readme/DESCRIPTION.rst b/l10n_fr_cog/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..d8c8399070 --- /dev/null +++ b/l10n_fr_cog/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module adds the *Code Officiel Géographique* of `INSEE `_ on countries. All countries except France and DOM-TOMs (and some very particular territories) have this code. + +This module is used by other modules of the French localization such as the DAS2 module. diff --git a/l10n_fr_cog/static/description/icon.png b/l10n_fr_cog/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/l10n_fr_cog/static/description/icon.png differ diff --git a/l10n_fr_cog/static/description/index.html b/l10n_fr_cog/static/description/index.html new file mode 100644 index 0000000000..618d4a9cd2 --- /dev/null +++ b/l10n_fr_cog/static/description/index.html @@ -0,0 +1,422 @@ + + + + + + +Code Officiel Géographique + + + +
+

Code Officiel Géographique

+ + +

Beta License: AGPL-3 OCA/l10n-france Translate me on Weblate Try me on Runbot

+

This module adds the Code Officiel Géographique of INSEE on countries. All countries except France and DOM-TOMs (and some very particular territories) have this code.

+

This module is used by other modules of the French localization such as the DAS2 module.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainer:

+

alexis-via

+

This module is part of the OCA/l10n-france project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_fr_cog/views/country.xml b/l10n_fr_cog/views/country.xml new file mode 100644 index 0000000000..8f81cec619 --- /dev/null +++ b/l10n_fr_cog/views/country.xml @@ -0,0 +1,32 @@ + + + + + + + l10n_fr_cog.res.country.form + res.country + + + + + + + + + + res.country + + + + + + + + + + diff --git a/l10n_fr_das2/README.rst b/l10n_fr_das2/README.rst new file mode 100644 index 0000000000..afb488df6e --- /dev/null +++ b/l10n_fr_das2/README.rst @@ -0,0 +1 @@ +Will be generated from readme subdir diff --git a/l10n_fr_das2/__init__.py b/l10n_fr_das2/__init__.py new file mode 100644 index 0000000000..aee8895e7a --- /dev/null +++ b/l10n_fr_das2/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/l10n_fr_das2/__manifest__.py b/l10n_fr_das2/__manifest__.py new file mode 100644 index 0000000000..1cee9b2755 --- /dev/null +++ b/l10n_fr_das2/__manifest__.py @@ -0,0 +1,31 @@ +# Copyright 2020-2023 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "DAS2", + "version": "15.0.1.0.0", + "category": "Invoicing Management", + "license": "AGPL-3", + "summary": "DAS2 (France)", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/l10n-france", + "depends": [ + "l10n_fr_siret", + "l10n_fr_cog", + ], + "external_dependencies": { + "python": ["stdnum", "pyfrdas2"], + }, + "data": [ + "security/das2_security.xml", + "security/ir.model.access.csv", + "views/l10n_fr_das2.xml", + "views/res_partner.xml", + "views/res_config_settings.xml", + ], + "demo": ["demo/demo.xml"], + "installable": True, + "application": True, +} diff --git a/l10n_fr_das2/demo/demo.xml b/l10n_fr_das2/demo/demo.xml new file mode 100644 index 0000000000..7937516d7c --- /dev/null +++ b/l10n_fr_das2/demo/demo.xml @@ -0,0 +1,69 @@ + + + + + + + + 6201Z + + + + + 999999998 + 00019 + + + + + + + Experts comptables du Rhône + 12 rue du chiffre + 69100 + Villeurbanne + + experts@comptables.example.com + fee + Expert comptable + 111111118 + 00019 + + + + + Cabinet d'avocats Juridon + 42 rue du crime + 69100 + Villeurbanne + + avocats@example.com + fee + Avocat + 222222226 + 00011 + + + + + Cabinet CACtus + 42 rue de l'audit + 69100 + Villeurbanne + + cac@example.com + fee + Commissaire aux comptes + 333333334 + 00014 + + + + diff --git a/l10n_fr_das2/i18n/fr.po b/l10n_fr_das2/i18n/fr.po new file mode 100644 index 0000000000..484bf6b5f6 --- /dev/null +++ b/l10n_fr_das2/i18n/fr.po @@ -0,0 +1,864 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_fr_das2 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-09-15 22:07+0000\n" +"Last-Translator: Claude R Perrin \n" +"Language-Team: none\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: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Lines Fullscreen" +msgstr "Lignes Plein écran" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_year_company_uniq +msgid "A DAS2 already exists for that year!" +msgstr "Une DAS2 existe déjà pour cette année !" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"A special character in the DAS2 file is not in the latin1 table. Please " +"locate this special character and replace it by a standard character and try " +"again." +msgstr "" +"Un caractère spécial dans le fichier DAS2 n'est pas dans le tableau latin1. " +"Veuillez remplacer ce caractère spécial et le remplacer par un caractère " +"standard et réessayer." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_needaction +msgid "Action Needed" +msgstr "Nécessite une action" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_ids +msgid "Activities" +msgstr "Activités" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "Activité d'exception de décoration" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_state +msgid "Activity State" +msgstr "État de l'Activité" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_type_icon +msgid "Activity Type Icon" +msgstr "Icône de type d'activité" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__contact_id +msgid "Administrative Contact" +msgstr "Contact administratif" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_fixed +msgid "Allocation forfaitaire" +msgstr "Allocation forfaitaire" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"An export file already exists. First, delete it via the attachments and then " +"re-generate it." +msgstr "" +"Un fichier d'exportation existe déjà. Tout d'abord, supprimez-le via les " +"pièces jointes, puis régénérez-le." + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Are you sure you want to go back to draft?" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_id +msgid "Attachment" +msgstr "Pièce jointe" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_attachment_count +msgid "Attachment Count" +msgstr "Nombre de pièces jointes" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__other_income_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__other_income +msgid "Autre rémunérations" +msgstr "Autres rémunérations" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_other +msgid "Autres" +msgstr "Autres" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_amount +msgid "Avantages en nature" +msgstr "Avantages en nature" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Back to Draft" +msgstr "Remettre en brouillon" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Cannot delete declaration %s in done state." +msgstr "Impossible de supprimer la déclaration %s en état terminé." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__commission_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__commission +msgid "Commissions" +msgstr "Commissions" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_company +msgid "Companies" +msgstr "Sociétés" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__company_id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__company_id +msgid "Company" +msgstr "Société" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"Company '%s' is configured in country '%s'. The DAS2 is only for France and " +"it's oversea territories." +msgstr "" +"L'entreprise '%s' est configurée dans le pays '%s'. Le DAS2 est réservé à la " +"France et ce sont des territoires d'outre-mer." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Company '%s' is configured with currency '%s'. It should be EUR." +msgstr "" +"L'entreprise '%s' est configurée avec la devise '%s'. Ça devrait être EUR." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__currency_id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__currency_id +msgid "Company Currency" +msgstr "Devise de la société" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_config_settings +msgid "Config Settings" +msgstr "Paramètres de config" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_partner +msgid "Contact" +msgstr "Contact" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__contact_id +msgid "" +"Contact in the company for the fiscal administration: the name, email and " +"phone number of this partner will be used in the file." +msgstr "" +"Contact dans l'entreprise pour l'administration fiscale : le nom, l'email et " +"le numéro de téléphone de ce partenaire seront utilisés dans le dossier." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Country not set on company '%s'." +msgstr "Pays non défini sur la société '%s'." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__brokerage_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__brokerage +msgid "Courtages" +msgstr "Courtages" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__create_uid +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__create_date +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__dads_type +msgid "DADS Type" +msgstr "Type de DADS" + +#. module: l10n_fr_das2 +#: model:ir.actions.act_window,name:l10n_fr_das2.l10n_fr_das2_action +#: model:ir.model,name:l10n_fr_das2.model_l10n_fr_das2 +#: model:ir.ui.menu,name:l10n_fr_das2.l10n_fr_das2_menu +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_tree +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_account_config_settings +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_res_partner_filter +msgid "DAS2" +msgstr "DAS2" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__fr_das2_job +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_users__fr_das2_job +msgid "DAS2 Job" +msgstr "Job DAS2" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_form +msgid "DAS2 Line" +msgstr "Ligne DAS2" + +#. module: l10n_fr_das2 +#: model:ir.actions.act_window,name:l10n_fr_das2.l10n_fr_das2_line_action +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_tree +msgid "DAS2 Lines" +msgstr "Lignes DAS2" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__fr_das2_partner_declare_threshold +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__fr_das2_partner_declare_threshold +msgid "DAS2 Partner Declaration Threshold" +msgstr "Seuil de déclaration du partenaire DAS2" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__parent_id +msgid "DAS2 Report" +msgstr "Rapport DAS2" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__fr_das2_type +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_users__fr_das2_type +msgid "DAS2 Type" +msgstr "Type DAS2" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 file deleted." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 file generated. Encrypted with DGFiP's %s PGP key." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_l10n_fr_das2_line +msgid "DAS2 line" +msgstr "Ligne DAS2" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 lines generated. " +msgstr "Lignes DAS2 générées. " + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__state__done +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Done" +msgstr "Fait" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__state__draft +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Draft" +msgstr "Brouillon" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__copyright_royalties_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__copyright_royalties +msgid "Droits d'auteur" +msgstr "Droits d'auteur" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__licence_royalties_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__licence_royalties +msgid "Droits d'inventeur" +msgstr "Droits de brevet" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Failed to convert field '%s' (partner %s) to integer." +msgstr "Impossible de convertir le champ '%s' (partenaire %s) en entier." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"Field %s (partner %s) has value %s: it is bigger than the maximum size (%d " +"characters)" +msgstr "" +"Le champ %s (partenaire %s) a la valeur %s : il est plus grand que la taille " +"maximale (%d caractères)" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_datas +msgid "File Export" +msgstr "Exporter le fichier" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_name +msgid "Filename" +msgstr "Nom du fichier" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_follower_ids +msgid "Followers" +msgstr "Abonnés" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_channel_ids +msgid "Followers (Channels)" +msgstr "Abonnés (Canaux)" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_partner_ids +msgid "Followers (Partners)" +msgstr "Abonnés (Partenaires)" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "Icône Font Awesome e.g. fa-tasks" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Generate Lines" +msgstr "Générer des lignes" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__fee_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__fee +msgid "Honoraires et vacations" +msgstr "Honoraires et vacances" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__id +msgid "ID" +msgstr "Identifiant" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_exception_icon +msgid "Icon" +msgstr "Icône" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "Icône pour indiquer une activité d'exception." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_needaction +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_unread +msgid "If checked, new messages require your attention." +msgstr "Si coché, de nouveaux messages demandent votre attention." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_error +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Si actif, certains messages ont une erreur de livraison." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__allowance +msgid "Indemnités et remboursements" +msgstr "Indemnités et remboursements" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_is_follower +msgid "Is Follower" +msgstr "Est un abonné" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__attendance_fee_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__attendance_fee +msgid "Jetons de présence" +msgstr "Jetons de présence" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +msgid "Job" +msgstr "Tache" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__dads_type__1 +msgid "La société ne verse pas de salaires" +msgstr "La société ne verse pas de salaires" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__dads_type__4 +msgid "La société verse des salaires" +msgstr "La société verse des salaires" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__write_uid +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__write_date +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__line_ids +msgid "Lines" +msgstr "Lignes" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "List view of lines" +msgstr "Vue en liste des lignes" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_accomodation +msgid "Logement" +msgstr "Logement" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_main_attachment_id +msgid "Main Attachment" +msgstr "Pièce jointe principale" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_error +msgid "Message Delivery error" +msgstr "Erreur d'envoi du message" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_ids +msgid "Messages" +msgstr "Messages" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing APE on company '%s'." +msgstr "APE manquant pour l'entreprise '%s'." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing Code Officiel Géographique on country '%s'." +msgstr "Code INSEE géographique manquant pour le pays '%s'." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIREN on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIRET for french partner %s." +msgstr "SIRET manquant pour le partenaire français %s." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIRET on company '%s'." +msgstr "SIRET manquant pour l'entreprise '%s'." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing Street on company '%s'" +msgstr "Rue manquante pour l'entreprise '%s'" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing administrative contact." +msgstr "Contact administratif manquant." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing city on partner '%s'." +msgstr "Ville manquante pour le partenaire '%s'." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "Échéance de mon activité" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_allowance_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_attendance_fee_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_benefits_in_kind_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_brokerage_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_commission_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_copyright_royalties_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_discount_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_fee_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_licence_royalties_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_other_income_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_withholding_tax_amount_positive +msgid "Negative amounts not allowed!" +msgstr "Montants négatifs ne sont pas autorisés !" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Date limite de l'Activité à Venir" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_summary +msgid "Next Activity Summary" +msgstr "Résumé d'activité suivante" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_type_id +msgid "Next Activity Type" +msgstr "Type d’activité suivante" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__note +msgid "Note" +msgstr "Note" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_form +msgid "Notes" +msgstr "Notes" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_food +msgid "Nourriture" +msgstr "Nourriture" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_needaction_counter +msgid "Number of Actions" +msgstr "Nombre d'actions" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_error_counter +msgid "Number of errors" +msgstr "Nombre d'erreurs" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "Nombre de messages exigeant une action" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Nombre de messages avec des erreurs d'envoi" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_unread_counter +msgid "Number of unread messages" +msgstr "Nombre de messages non lus" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"One of the lines has a length of %d. All lines should have a length of 672. " +"Line: %s." +msgstr "" +"L'une des lignes a une longueur de %d. Toutes les lignes doivent avoir une " +"longueur de 672. Ligne : %s." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_nict +msgid "Outils issus des NTIC" +msgstr "Outils issus des NTIC" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__partner_declare_threshold +msgid "Partner Declaration Threshold" +msgstr "Seuil de déclaration du partenaire" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__payment_journal_ids +msgid "Payment Journals" +msgstr "Journaux de paiement" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Payment dated %s in journal '%s': %.2f € (journal entry %s)" +msgstr "" +"Paiement en date du %s dans le journal '%s' : %.2f € ( écriture de journal " +"%s)" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_employer +msgid "Prise en charge directe par l'employeur" +msgstr "Prise en charge directe par l'employeur" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__job +msgid "Profession" +msgstr "Activité" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_user_id +msgid "Responsible User" +msgstr "Utilisateur Responsable" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__withholding_tax_amount +msgid "Retenue à la source" +msgstr "Retenue à la source" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__discount_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__discount +msgid "Ristournes" +msgstr "Ristournes" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__partner_siret +msgid "SIRET" +msgstr "SIRET" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "SIRET '%s' is invalid." +msgstr "Le SIRET '%s' est invalide." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_sms_error +msgid "SMS Delivery error" +msgstr "Erreur de livraison du SMS" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_partner_parent_unique +msgid "Same partner used on several lines!" +msgstr "Même partenaire utilisé sur plusieurs lignes !" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Search DAS2" +msgstr "Rechercher DAS2" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_search +msgid "Search DAS2 Lines" +msgstr "Rechercher des lignes DAS2" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__state +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__state +msgid "State" +msgstr "État" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" +"État basé sur les activités\n" +"En retard : la date d'échéance est déjà dépassée\n" +"Aujourd'hui : la date d'activité est aujourd'hui\n" +"Planifiée : activités futures." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__partner_id +msgid "Supplier" +msgstr "Fournisseur" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_real +msgid "Sur frais réels" +msgstr "Sur frais réels" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The DAS2 has no lines." +msgstr "La DAS2 n'a pas de lignes." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The DAS2 partner declaration threshold is not set on company '%s'." +msgstr "" +"Le seuil de déclaration du partenaire DAS2 n'est pas défini sur la société " +"'%s'." + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_res_company_fr_das2_partner_declare_threshold_positive +msgid "The DAS2 partner declaration threshold must be positive!" +msgstr "Le seuil de déclaration du partenaire DAS2 doit être positif !" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The email is not set on the administrative contact partner '%s'." +msgstr "" +"L'e-mail n'est pas défini sur le partenaire de contact administratif '%s'." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"The field '%s' (partner %s) is empty or 0. It should have a non-null value." +msgstr "" +"Le champ '%s' (partenaire %s) est vide ou à zéro. Il devrait avoir une " +"valeur non nulle." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"The following partners are not configured for DAS2 but they have expenses in " +"some accounts that indicate they should probably be configured for DAS2:
    " +msgstr "" +"Les partenaires suivants ne sont pas configurés pour DAS2, mais ils ont des " +"dépenses dans certains comptes qui indiquent qu'ils devraient probablement " +"être configurés pour DAS2 :
      " + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The phone number is not set on the administrative contact partner '%s'." +msgstr "" +"Le numéro de téléphone n'est pas défini sur le partenaire de contact " +"administratif '%s'." + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "There are no partners configured for DAS2." +msgstr "Il n'y a pas de partenaires configurés pour la DAS2." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__to_declare +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_search +msgid "To Declare" +msgstr "A déclarer" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__total_amount +msgid "Total Amount" +msgstr "Montant total" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +msgid "Type" +msgstr "Type" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Type d'activité d'exception enregistrée." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__unencrypted_attachment_id +msgid "Unencrypted Attachment" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_unread +msgid "Unread Messages" +msgstr "Messages non lus" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_unread_counter +msgid "Unread Messages Counter" +msgstr "Compteur de messages non lus" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_res_partner__fr_das2_job +#: model:ir.model.fields,help:l10n_fr_das2.field_res_users__fr_das2_job +msgid "Used in the field 'Profession' of DAS2." +msgstr "Utilisé dans le champ 'Profession' de la DAS2." + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_car +msgid "Voiture" +msgstr "Voiture" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__warning_msg +msgid "Warning Msg" +msgstr "Msg d’alerte" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__website_message_ids +msgid "Website Messages" +msgstr "Messages du site web" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__website_message_ids +msgid "Website communication history" +msgstr "Historique de communication du site web" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__year +msgid "Year" +msgstr "Année" + +#, python-format +#~ msgid "DAS2 file generated." +#~ msgstr "Fichier DAS2 généré." + +#~ msgid "Generate File" +#~ msgstr "Générer un fichier" diff --git a/l10n_fr_das2/i18n/l10n_fr_das2.pot b/l10n_fr_das2/i18n/l10n_fr_das2.pot new file mode 100644 index 0000000000..83c25c1c09 --- /dev/null +++ b/l10n_fr_das2/i18n/l10n_fr_das2.pot @@ -0,0 +1,826 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_fr_das2 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.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: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Lines Fullscreen" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_year_company_uniq +msgid "A DAS2 already exists for that year!" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"A special character in the DAS2 file is not in the latin1 table. Please " +"locate this special character and replace it by a standard character and try" +" again." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_ids +msgid "Activities" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_state +msgid "Activity State" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__contact_id +msgid "Administrative Contact" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_fixed +msgid "Allocation forfaitaire" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"An export file already exists. First, delete it via the attachments and then" +" re-generate it." +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Are you sure you want to go back to draft?" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_id +msgid "Attachment" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__other_income_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__other_income +msgid "Autre rémunérations" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_other +msgid "Autres" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_amount +msgid "Avantages en nature" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Back to Draft" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Cannot delete declaration %s in done state." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__commission_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__commission +msgid "Commissions" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_company +msgid "Companies" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__company_id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__company_id +msgid "Company" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"Company '%s' is configured in country '%s'. The DAS2 is only for France and " +"it's oversea territories." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Company '%s' is configured with currency '%s'. It should be EUR." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__currency_id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__currency_id +msgid "Company Currency" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_res_partner +msgid "Contact" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__contact_id +msgid "" +"Contact in the company for the fiscal administration: the name, email and " +"phone number of this partner will be used in the file." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Country not set on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__brokerage_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__brokerage +msgid "Courtages" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__create_uid +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__create_uid +msgid "Created by" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__create_date +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__create_date +msgid "Created on" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__dads_type +msgid "DADS Type" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.actions.act_window,name:l10n_fr_das2.l10n_fr_das2_action +#: model:ir.model,name:l10n_fr_das2.model_l10n_fr_das2 +#: model:ir.ui.menu,name:l10n_fr_das2.l10n_fr_das2_menu +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_tree +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_account_config_settings +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_res_partner_filter +msgid "DAS2" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__fr_das2_job +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_users__fr_das2_job +msgid "DAS2 Job" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_form +msgid "DAS2 Line" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.actions.act_window,name:l10n_fr_das2.l10n_fr_das2_line_action +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_tree +msgid "DAS2 Lines" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__fr_das2_partner_declare_threshold +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__fr_das2_partner_declare_threshold +msgid "DAS2 Partner Declaration Threshold" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__parent_id +msgid "DAS2 Report" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__fr_das2_type +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_users__fr_das2_type +msgid "DAS2 Type" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 file deleted." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 file generated. Encrypted with DGFiP's %s PGP key." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model,name:l10n_fr_das2.model_l10n_fr_das2_line +msgid "DAS2 line" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "DAS2 lines generated. " +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__display_name +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__state__done +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Done" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__state__draft +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Draft" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__copyright_royalties_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__copyright_royalties +msgid "Droits d'auteur" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__licence_royalties_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__licence_royalties +msgid "Droits d'inventeur" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Failed to convert field '%s' (partner %s) to integer." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"Field %s (partner %s) has value %s: it is bigger than the maximum size (%d " +"characters)" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_datas +msgid "File Export" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__attachment_name +msgid "Filename" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "Generate Lines" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__fee_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__fee +msgid "Honoraires et vacations" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings__id +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner__id +msgid "ID" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_needaction +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_unread +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_error +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__allowance +msgid "Indemnités et remboursements" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__attendance_fee_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__attendance_fee +msgid "Jetons de présence" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +msgid "Job" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__dads_type__1 +msgid "La société ne verse pas de salaires" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__l10n_fr_das2__dads_type__4 +msgid "La société verse des salaires" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_company____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_config_settings____last_update +#: model:ir.model.fields,field_description:l10n_fr_das2.field_res_partner____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__write_uid +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__write_date +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__line_ids +msgid "Lines" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_form +msgid "List view of lines" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_accomodation +msgid "Logement" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_ids +msgid "Messages" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing APE on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing Code Officiel Géographique on country '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIREN on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIRET for french partner %s." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing SIRET on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing Street on company '%s'" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing administrative contact." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Missing city on partner '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_allowance_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_attendance_fee_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_benefits_in_kind_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_brokerage_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_commission_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_copyright_royalties_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_discount_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_fee_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_licence_royalties_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_other_income_amount_positive +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_withholding_tax_amount_positive +msgid "Negative amounts not allowed!" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__note +msgid "Note" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_form +msgid "Notes" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_food +msgid "Nourriture" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"One of the lines has a length of %d. All lines should have a length of 672. " +"Line: %s." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_nict +msgid "Outils issus des NTIC" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__partner_declare_threshold +msgid "Partner Declaration Threshold" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__payment_journal_ids +msgid "Payment Journals" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "Payment dated %s in journal '%s': %.2f € (journal entry %s)" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_employer +msgid "Prise en charge directe par l'employeur" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__job +msgid "Profession" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__withholding_tax_amount +msgid "Retenue à la source" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__discount_amount +#: model:ir.model.fields.selection,name:l10n_fr_das2.selection__res_partner__fr_das2_type__discount +msgid "Ristournes" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__partner_siret +msgid "SIRET" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "SIRET '%s' is invalid." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_has_sms_error +msgid "SMS Delivery error" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_l10n_fr_das2_line_partner_parent_unique +msgid "Same partner used on several lines!" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_search +msgid "Search DAS2" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_search +msgid "Search DAS2 Lines" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__state +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__state +msgid "State" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__partner_id +msgid "Supplier" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__allowance_real +msgid "Sur frais réels" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The DAS2 has no lines." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The DAS2 partner declaration threshold is not set on company '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.constraint,message:l10n_fr_das2.constraint_res_company_fr_das2_partner_declare_threshold_positive +msgid "The DAS2 partner declaration threshold must be positive!" +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "The email is not set on the administrative contact partner '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"The field '%s' (partner %s) is empty or 0. It should have a non-null value." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"The following partners are not configured for DAS2 but they have expenses in" +" some accounts that indicate they should probably be configured for " +"DAS2:
        " +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "" +"The phone number is not set on the administrative contact partner '%s'." +msgstr "" + +#. module: l10n_fr_das2 +#: code:addons/l10n_fr_das2/models/l10n_fr_das2.py:0 +#, python-format +msgid "There are no partners configured for DAS2." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__to_declare +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.l10n_fr_das2_line_search +msgid "To Declare" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__total_amount +msgid "Total Amount" +msgstr "" + +#. module: l10n_fr_das2 +#: model_terms:ir.ui.view,arch_db:l10n_fr_das2.view_partner_property_form +msgid "Type" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__unencrypted_attachment_id +msgid "Unencrypted Attachment" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_res_partner__fr_das2_job +#: model:ir.model.fields,help:l10n_fr_das2.field_res_users__fr_das2_job +msgid "Used in the field 'Profession' of DAS2." +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2_line__benefits_in_kind_car +msgid "Voiture" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__warning_msg +msgid "Warning Msg" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,help:l10n_fr_das2.field_l10n_fr_das2__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: l10n_fr_das2 +#: model:ir.model.fields,field_description:l10n_fr_das2.field_l10n_fr_das2__year +msgid "Year" +msgstr "" diff --git a/l10n_fr_das2/models/__init__.py b/l10n_fr_das2/models/__init__.py new file mode 100644 index 0000000000..cb3d3203f6 --- /dev/null +++ b/l10n_fr_das2/models/__init__.py @@ -0,0 +1,3 @@ +from . import l10n_fr_das2 +from . import res_partner +from . import res_company diff --git a/l10n_fr_das2/models/l10n_fr_das2.py b/l10n_fr_das2/models/l10n_fr_das2.py new file mode 100644 index 0000000000..1bdfebd8aa --- /dev/null +++ b/l10n_fr_das2/models/l10n_fr_das2.py @@ -0,0 +1,974 @@ +# Copyright 2020-2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import logging +from datetime import datetime + +from pyfrdas2 import format_street_block, generate_file +from stdnum.fr.siret import is_valid + +from odoo import _, api, fields, models, tools +from odoo.exceptions import UserError, ValidationError +from odoo.tools.misc import format_amount, format_date + +logger = logging.getLogger(__name__) + + +FRANCE_CODES = ( + "FR", + "GP", + "MQ", + "GF", + "RE", + "YT", + "NC", + "PF", + "TF", + "MF", + "BL", + "PM", + "WF", +) +AMOUNT_FIELDS = [ + "fee_amount", + "commission_amount", + "brokerage_amount", + "discount_amount", + "attendance_fee_amount", + "copyright_royalties_amount", + "licence_royalties_amount", + "other_income_amount", + "allowance_amount", + "benefits_in_kind_amount", + "withholding_tax_amount", +] + + +class L10nFrDas2(models.Model): + _name = "l10n.fr.das2" + _inherit = ["mail.thread", "mail.activity.mixin"] + _order = "year desc" + _description = "DAS2" + _check_company_auto = True + + year = fields.Integer( + required=True, + states={"done": [("readonly", True)]}, + tracking=True, + default=lambda self: self._default_year(), + index=True, + ) + state = fields.Selection( + [ + ("draft", "Draft"), + ("done", "Done"), + ], + default="draft", + readonly=True, + tracking=True, + index=True, + ) + company_id = fields.Many2one( + "res.company", + ondelete="cascade", + required=True, + states={"done": [("readonly", True)]}, + default=lambda self: self.env.company, + ) + currency_id = fields.Many2one( + related="company_id.currency_id", + store=True, + string="Company Currency", + ) + payment_journal_ids = fields.Many2many( + "account.journal", + string="Payment Journals", + required=True, + default=lambda self: self._default_payment_journals(), + domain="[('company_id', '=', company_id)]", + states={"done": [("readonly", True)]}, + check_company=True, + ) + line_ids = fields.One2many( + "l10n.fr.das2.line", + "parent_id", + string="Lines", + states={"done": [("readonly", True)]}, + ) + partner_declare_threshold = fields.Integer( + string="Partner Declaration Threshold", readonly=True + ) + dads_type = fields.Selection( + [ + ("4", "La société verse des salaires"), + ("1", "La société ne verse pas de salaires"), + ], + "DADS Type", + required=True, + states={"done": [("readonly", True)]}, + tracking=True, + default=lambda self: self._default_dads_type(), + ) + # option for draft moves ? + contact_id = fields.Many2one( + "res.partner", + string="Administrative Contact", + states={"done": [("readonly", True)]}, + default=lambda self: self.env.user.partner_id.id, + tracking=True, + help="Contact in the company for the fiscal administration: the name, " + "email and phone number of this partner will be used in the file.", + ) + attachment_id = fields.Many2one("ir.attachment", readonly=True) + attachment_datas = fields.Binary( + related="attachment_id.datas", string="File Export" + ) + attachment_name = fields.Char(related="attachment_id.name", string="Filename") + unencrypted_attachment_id = fields.Many2one( + "ir.attachment", string="Unencrypted Attachment", readonly=True + ) + # The only drawback of the warning_msg solution is that I didn't find a way + # to put a link to partners inside it + warning_msg = fields.Html(readonly=True) + + _sql_constraints = [ + ( + "year_company_uniq", + "unique(company_id, year)", + "A DAS2 already exists for that year!", + ) + ] + + @api.model + def _default_dads_type(self): + previous_decl = self.search( + [("dads_type", "!=", False)], order="year desc", limit=1 + ) + if previous_decl: + return previous_decl.dads_type + else: + return "4" + + @api.model + def _default_payment_journals(self): + res = [] + pay_journals = self.env["account.journal"].search( + [("type", "in", ("bank", "cash")), ("company_id", "=", self.env.company.id)] + ) + if pay_journals: + res = pay_journals.ids + return res + + @api.model + def _default_year(self): + last_year = datetime.today().year - 1 + return last_year + + @api.depends("year") + def name_get(self): + res = [] + for rec in self: + res.append((rec.id, "DAS2 %s" % rec.year)) + return res + + def done(self): + self.ensure_one() + vals = {"state": "done"} + if self.line_ids: + running_env = tools.config.get("running_env") + if running_env in ("test", "dev"): + encryption = "test" + else: + encryption = "prod" + msg = ( + _("DAS2 file generated. Encrypted with DGFiP's %s PGP key.") + % encryption + ) + + attach = self.generate_file_and_attach(encryption=encryption) + self.message_post(body=msg) + # also generate a clear file, for audit purposes + unencrypted_attach = self.generate_file_and_attach(encryption="none") + vals.update( + { + "attachment_id": attach.id, + "unencrypted_attachment_id": unencrypted_attach.id, + } + ) + self.write(vals) + return + + def back2draft(self): + self.ensure_one() + if self.attachment_id: + self.attachment_id.unlink() + self.message_post(body=_("DAS2 file deleted.")) + if self.unencrypted_attachment_id: + self.unencrypted_attachment_id.unlink() + self.write({"state": "draft"}) + return + + def unlink(self): + for rec in self: + if rec.state == "done": + raise UserError( + _("Cannot delete declaration %s in done state.") % rec.display_name + ) + return super().unlink() + + def generate_lines(self): + self.ensure_one() + lfdlo = self.env["l10n.fr.das2.line"] + company = self.company_id + if not company.country_id: + raise UserError( + _("Country not set on company '%s'.") % company.display_name + ) + if company.country_id.code not in FRANCE_CODES: + raise UserError( + _( + "Company '%(company)s' is configured in country '%(country)s'. " + "The DAS2 is only for France and it's oversea territories.", + company=company.display_name, + country=company.country_id.name, + ) + ) + if company.currency_id != self.env.ref("base.EUR"): + raise UserError( + _( + "Company '%(company)s' is configured with currency '%(currency)s'. " + "It should be EUR.", + company=company.display_name, + currency=company.currency_id.name, + ) + ) + if company.fr_das2_partner_declare_threshold <= 0: + raise UserError( + _( + "The DAS2 partner declaration threshold is not set on " + "company '%s'." + ) + % company.display_name + ) + self.partner_declare_threshold = company.fr_das2_partner_declare_threshold + das2_partners = self.env["res.partner"].search( + [("parent_id", "=", False), ("fr_das2_type", "!=", False)] + ) + if not das2_partners: + raise UserError(_("There are no partners configured for DAS2.")) + self.line_ids.unlink() + base_domain = [ + ("company_id", "=", self.company_id.id), + ("date", ">=", "%d-01-01" % self.year), + ("date", "<=", "%d-12-31" % self.year), + ("journal_id", "in", self.payment_journal_ids.ids), + ("balance", "!=", 0), + ("parent_state", "=", "posted"), + ] + for partner in das2_partners: + vals = self._prepare_line(partner, base_domain) + if vals: + lfdlo.create(vals) + self.generate_warning_msg(das2_partners) + + def _prepare_line(self, partner, base_domain): + amlo = self.env["account.move.line"] + mlines = amlo.search( + base_domain + + [ + ("partner_id", "=", partner.id), + ("account_id", "=", partner.property_account_payable_id.id), + ] + ) + note = "" + amount = 0.0 + for mline in mlines: + amount += mline.balance + note_text = _( + "Payment dated %(date)s in journal %(journal)s: " + "%(amount)s (journal entry %(move_name)s)", + date=format_date(self.env, mline.date), + journal=mline.journal_id.display_name, + amount=format_amount(self.env, mline.balance, self.currency_id), + move_name=mline.move_id.name, + ) + note += "
      • %s
      • " % note_text + res = False + amount_int = int(round(amount)) + if note and amount_int > 0: + field_name = "%s_amount" % partner.fr_das2_type + res = { + field_name: amount_int, + "parent_id": self.id, + "partner_id": partner.id, + "note": "
          %s
        " % note, + } + return res + + def generate_warning_msg(self, das2_partners): + amlo = self.env["account.move.line"] + aao = self.env["account.account"] + ajo = self.env["account.journal"] + rpo = self.env["res.partner"] + company = self.company_id + purchase_journals = ajo.search( + [("type", "=", "purchase"), ("company_id", "=", company.id)] + ) + das2_accounts = aao.search( + [ + ("company_id", "=", company.id), + "|", + "|", + "|", + "|", + "|", + ("code", "=like", "6221%"), + ("code", "=like", "6222%"), + ("code", "=like", "6226%"), + ("code", "=like", "6228%"), + ("code", "=like", "653%"), + ("code", "=like", "6516%"), + ] + ) + rg_res = amlo.read_group( + [ + ("company_id", "=", company.id), + ("date", ">=", "%d-10-01" % (self.year - 1)), + ("date", "<=", "%d-12-31" % self.year), + ("journal_id", "in", purchase_journals.ids), + ("partner_id", "!=", False), + ("partner_id", "not in", das2_partners.ids), + ("account_id", "in", das2_accounts.ids), + ("balance", "!=", 0), + ("parent_state", "=", "posted"), + ], + ["partner_id"], + ["partner_id"], + ) + msg = False + msg_post = _("DAS2 lines generated. ") + if rg_res: + msg = _( + "The following partners are not configured for DAS2 but " + "they have expenses in some accounts that indicate " + "they should probably be configured for DAS2:
          " + ) + msg_post += msg + for rg_re in rg_res: + partner = rpo.browse(rg_re["partner_id"][0]) + msg_post += ( + '
        • %s
        • ' % (partner.id, partner.display_name) + ) + msg += "
        • %s
        • " % partner.display_name + msg_post += "
        " + msg += "
      " + self.message_post(body=msg_post) + self.write({"warning_msg": msg}) + + @api.model + def _prepare_field( + self, field_name, partner, value, size, required=False, numeric=False + ): + """This function is designed to be inherited.""" + if numeric: + if not value: + value = 0 + if not isinstance(value, int): + try: + value = int(value) + except Exception as e: + raise UserError( + _( + "Failed to convert field '%(field_name)s' " + "(partner %(partner)s) to integer.", + field_name=field_name, + partner=partner.display_name, + ) + ) from e + value = str(value) + if len(value) > size: + raise UserError( + _( + "Field %(field_name)s (partner %(partner)s) has value " + "%(value)s: it is bigger than the maximum size " + "(%(size)d characters).", + field_name=field_name, + partner=partner.display_name, + value=value, + size=size, + ) + ) + if len(value) < size: + value = value.rjust(size, "0") + return value + if required and not value: + raise UserError( + _( + "The field '%(field_name)s' (partner %(partner)s) is empty or 0. " + "It should have a non-null value.", + field_name=field_name, + partner=partner.display_name, + ) + ) + if not value: + value = " " * size + # Cut if too long + value = value[0:size] + # enlarge if too small + if len(value) < size: + value = value.ljust(size, " ") + return value + + def _prepare_address(self, partner): + cstreet2 = self._prepare_field("Street2", partner, partner.street2, 32) + cstreet = format_street_block(partner.street) + # specs : only bureau distributeur and code postal are + # required. And they say it is tolerated to set city as + # bureau distributeur + # And we don't set the commune field because we put the same info + # in bureau distributeur + # specs 2024 : we now have to have structured adresses with a separation + # for the number, bis/ter and street name. We'll do our best to comply with that. + if not partner.city: + raise UserError(_("Missing city on partner '%s'.") % partner.display_name) + if partner.country_id and partner.country_id.code not in FRANCE_CODES: + if not partner.country_id.fr_cog: + raise UserError( + _("Missing Code Officiel Géographique on country '%s'.") + % partner.country_id.display_name + ) + cog = self._prepare_field( + "COG", partner, partner.country_id.fr_cog, 5, True, numeric=True + ) + raw_country_name = partner.with_context(lang="fr_FR").country_id.name + country_name = self._prepare_field( + "Nom du pays", partner, raw_country_name, 26, True + ) + raw_commune = partner.city + if partner.zip: + raw_commune = "{} {}".format(partner.zip, partner.city) + commune = self._prepare_field("Commune", partner, raw_commune, 26, True) + caddress = ( + cstreet2 + + " " + + cstreet + + cog + + " " + + commune + + cog + + " " + + country_name + ) + # According to the specs, we should have some code specific for DOM-TOM + # But it's not easy, because we are supposed to give the INSEE code + # of the city, not of the territory => we don't handle that for the + # moment + else: + ccity = self._prepare_field("City", partner, partner.city, 26, True) + czip = self._prepare_field("Zip", partner, partner.zip, 5, True) + caddress = ( + cstreet2 + " " + cstreet + "0" * 5 + " " + " " * 26 + czip + " " + ccity + ) + assert len(caddress) == 129 + return caddress + + def _prepare_file(self): + company = self.company_id + cpartner = company.partner_id + contact = self.contact_id + csiren = self._prepare_field("SIREN", cpartner, cpartner.siren, 9, True) + csiret = self._prepare_field("SIRET", cpartner, cpartner.siret, 14, True) + cape = self._prepare_field("APE", cpartner, company.ape, 5, True) + cname = self._prepare_field("Name", cpartner, company.name, 50, True) + file_type = "X" # tous déclarants honoraires seuls + year = str(self.year) + assert len(year) == 4 + caddress = self._prepare_address(cpartner) + cprefix = csiret + "01" + year + self.dads_type + # line 010 Company header + flines = [] + flines.append( + csiren + + "0" * 12 + + "010" + + " " * 14 + + cape + + " " * 4 + + cname + + caddress + + " " * 8 + + file_type + + csiret + + " " * 5 + + caddress + + " " + + " " * 288 + ) + + # ligne 020 Etablissement header + # We don't add a field for profession on the company + # because it's not even a field on the paper form! + # We only set profession for suppliers + flines.append( + cprefix + + "020" + + " " * 14 + + cape + + "0" * 14 + + " " * 41 + + cname + + caddress + + " " * 40 + + " " * 53 + + "N" + + " " * 3 + + "N" + + " " * 297 + ) + + i = 0 + for line in self.line_ids.filtered(lambda x: x.to_declare): + i += 1 + partner = line.partner_id + if ( + partner.country_id + and partner.country_id.code in FRANCE_CODES + and not line.partner_siret + ): + raise UserError( + _("Missing SIRET for french partner %s.") % partner.display_name + ) + # ligne 210 honoraire + if partner.is_company: + partner_name = self._prepare_field( + "Partner name", partner, partner.name, 50, True + ) + lastname = " " * 30 + firstname = " " * 20 + else: + partner_name = " " * 50 + if hasattr(partner, "firstname") and partner.firstname: + lastname = self._prepare_field( + "Lastname", partner, partner.lastname, 30, True + ) + firstname = self._prepare_field( + "Firstname", partner, partner.firstname, 20, True + ) + else: + lastname = self._prepare_field( + "Partner name", partner, partner.name, 30, True + ) + firstname = " " * 20 + address = self._prepare_address(partner) + partner_siret = self._prepare_field( + "SIRET", partner, line.partner_siret, 14 + ) + job = self._prepare_field("Profession", partner, line.job, 30) + amount_fields_list = [ + self._prepare_field(x, partner, line[x], 10, numeric=True) + for x in AMOUNT_FIELDS + ] + if line.benefits_in_kind_amount: + bik_letters = "" + bik_letters += line.benefits_in_kind_food and "N" or " " + bik_letters += line.benefits_in_kind_accomodation and "L" or " " + bik_letters += line.benefits_in_kind_car and "V" or " " + bik_letters += line.benefits_in_kind_other and "A" or " " + bik_letters += line.benefits_in_kind_nict and "T" or " " + else: + bik_letters = " " * 5 + if line.allowance_amount: + allow_letters = "" + allow_letters += line.allowance_fixed and "F" or " " + allow_letters += line.allowance_real and "R" or " " + allow_letters += line.allowance_employer and "P" or " " + else: + allow_letters = " " * 3 + flines.append( + cprefix + + "210" + + partner_siret + + lastname + + firstname + + partner_name + + job + + address + + "".join(amount_fields_list) + + bik_letters + + allow_letters + + " " * 2 + + "0" * 10 + + " " * 245 + ) + rg = self.env["l10n.fr.das2.line"].read_group( + [("parent_id", "=", self.id)], AMOUNT_FIELDS, [] + )[0] + total_fields_list = [ + self._prepare_field(x, cpartner, rg[x], 12, numeric=True) + for x in AMOUNT_FIELDS + ] + contact_name = self._prepare_field( + "Administrative contact name", contact, contact.name, 50 + ) + contact_email = self._prepare_field( + "Administrative contact email", contact, contact.email, 60 + ) + phone = contact.phone or contact.mobile + phone = ( + phone.replace(" ", "") + .replace(".", "") + .replace("-", "") + .replace("\u00A0", "") + ) + if phone.startswith("+33"): + phone = "0%s" % phone[3:] + contact_phone = self._prepare_field( + "Administrative contact phone", contact, phone, 10 + ) + # Total Etablissement + flines.append( + cprefix + + "300" + + " " * 36 + + "0" * 12 * 9 + + "".join(total_fields_list) + + " " * 12 + + "0" * 12 * 2 + + "0" * 6 + + " " * 48 + + "0" * 12 + + " " * 74 + + contact_name + + contact_phone + + contact_email + + csiren + + " " * 67 + ) + + lines_number = self._prepare_field( + "Number of lines", cpartner, i, 6, numeric=True + ) + # Total Entreprise + flines.append( + csiren + + "9" * 12 + + "310" + + "00001" + + "0" * 6 + + lines_number + + " " * 36 + + "0" * 12 * 9 + + "".join(total_fields_list) + + " " * 12 + + "0" * 12 * 2 + + "0" * 6 + + " " * 48 + + "0" * 12 + + " " * 253 + ) + for fline in flines: + if len(fline) != 672: + raise UserError( + _( + "One of the lines has a length of %(length)d. " + "All lines should have a length of 672. Line: %(line_content)s.", + length=len(fline), + line_content=fline, + ) + ) + file_content = "\r\n".join(flines) + "\r\n" + return file_content + + def generate_file_and_attach(self, encryption="prod"): + self.ensure_one() + assert encryption in ("prod", "test", "none") + company = self.company_id + if not self.line_ids: + raise UserError(_("The DAS2 has no lines.")) + if not company.siret: + raise UserError(_("Missing SIRET on company '%s'.") % company.display_name) + if not company.siren: + raise UserError(_("Missing SIREN on company '%s'.") % company.display_name) + if not company.ape: + raise UserError(_("Missing APE on company '%s'.") % company.display_name) + if not company.street: + raise UserError(_("Missing Street on company '%s'") % company.display_name) + contact = self.contact_id + if not contact: + raise UserError(_("Missing administrative contact.")) + if not contact.email: + raise UserError( + _("The email is not set on the administrative contact " "partner '%s'.") + % contact.display_name + ) + if not contact.phone and not contact.mobile: + raise UserError( + _( + "The phone number is not set on the administrative contact " + "partner '%s'." + ) + % contact.display_name + ) + if self.attachment_id: + raise UserError( + _( + "An export file already exists. First, delete it via the " + "attachments and then re-generate it." + ) + ) + + file_content = self._prepare_file() + try: + file_content_encoded = file_content.encode("latin1") + except UnicodeEncodeError as e: + raise UserError( + _( + "A special character in the DAS2 file is not in the latin1 " + "table. Please locate this special character and replace " + "it by a standard character and try again." + ) + ) from e + + try: + file_bytes_result, filename = generate_file( + file_content_encoded, self.year, company.siren, encryption=encryption + ) + except Exception as e: + raise UserError(e) from e + + attach = self.env["ir.attachment"].create( + { + "name": filename, + "res_id": self.id, + "res_model": self._name, + "datas": base64.encodebytes(file_bytes_result), + } + ) + return attach + + def button_lines_fullscreen(self): + self.ensure_one() + action = self.env.ref("l10n_fr_das2.l10n_fr_das2_line_action").sudo().read()[0] + action.update( + { + "domain": [("parent_id", "=", self.id)], + "views": False, + } + ) + return action + + +class L10nFrDas2Line(models.Model): + _name = "l10n.fr.das2.line" + _description = "DAS2 line" + + parent_id = fields.Many2one( + "l10n.fr.das2", string="DAS2 Report", ondelete="cascade" + ) + partner_id = fields.Many2one( + "res.partner", + string="Supplier", + ondelete="restrict", + domain=[("parent_id", "=", False)], + states={"done": [("readonly", True)]}, + required=True, + ) + partner_siret = fields.Char( + compute="_compute_partner_siret", + store=True, + readonly=False, + string="SIRET", + size=14, + states={"done": [("readonly", True)]}, + ) + company_id = fields.Many2one(related="parent_id.company_id", store=True) + currency_id = fields.Many2one( + related="parent_id.company_id.currency_id", + store=True, + string="Company Currency", + ) + fee_amount = fields.Integer( + string="Honoraires et vacations", states={"done": [("readonly", True)]} + ) + commission_amount = fields.Integer( + string="Commissions", states={"done": [("readonly", True)]} + ) + brokerage_amount = fields.Integer( + string="Courtages", states={"done": [("readonly", True)]} + ) + discount_amount = fields.Integer( + string="Ristournes", states={"done": [("readonly", True)]} + ) + attendance_fee_amount = fields.Integer( + string="Jetons de présence", states={"done": [("readonly", True)]} + ) + copyright_royalties_amount = fields.Integer( + string="Droits d'auteur", states={"done": [("readonly", True)]} + ) + licence_royalties_amount = fields.Integer( + string="Droits d'inventeur", states={"done": [("readonly", True)]} + ) + other_income_amount = fields.Integer( + string="Autre rémunérations", states={"done": [("readonly", True)]} + ) + allowance_amount = fields.Integer( + string="Indemnités et remboursements", states={"done": [("readonly", True)]} + ) + benefits_in_kind_amount = fields.Integer( + string="Avantages en nature", states={"done": [("readonly", True)]} + ) + withholding_tax_amount = fields.Integer( + string="Retenue à la source", states={"done": [("readonly", True)]} + ) + total_amount = fields.Integer( + compute="_compute_total_amount", + store=True, + readonly=True, + ) + to_declare = fields.Boolean( + compute="_compute_total_amount", readonly=True, store=True + ) + allowance_fixed = fields.Boolean( + "Allocation forfaitaire", states={"done": [("readonly", True)]} + ) + allowance_real = fields.Boolean( + "Sur frais réels", states={"done": [("readonly", True)]} + ) + allowance_employer = fields.Boolean( + "Prise en charge directe par l'employeur", states={"done": [("readonly", True)]} + ) + benefits_in_kind_food = fields.Boolean( + "Nourriture", states={"done": [("readonly", True)]} + ) + benefits_in_kind_accomodation = fields.Boolean( + "Logement", states={"done": [("readonly", True)]} + ) + benefits_in_kind_car = fields.Boolean( + "Voiture", states={"done": [("readonly", True)]} + ) + benefits_in_kind_other = fields.Boolean( + "Autres", states={"done": [("readonly", True)]} + ) + benefits_in_kind_nict = fields.Boolean( + "Outils issus des NTIC", states={"done": [("readonly", True)]} + ) + state = fields.Selection(related="parent_id.state", store=True) + note = fields.Html() + job = fields.Char( + compute="_compute_job", + store=True, + readonly=False, + string="Profession", + size=30, + states={"done": [("readonly", True)]}, + ) + + _sql_constraints = [ + ( + "partner_parent_unique", + "unique(partner_id, parent_id)", + "Same partner used on several lines!", + ), + ( + "fee_amount_positive", + "CHECK(fee_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "commission_amount_positive", + "CHECK(commission_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "brokerage_amount_positive", + "CHECK(brokerage_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "discount_amount_positive", + "CHECK(discount_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "attendance_fee_amount_positive", + "CHECK(attendance_fee_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "copyright_royalties_amount_positive", + "CHECK(copyright_royalties_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "licence_royalties_amount_positive", + "CHECK(licence_royalties_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "other_income_amount_positive", + "CHECK(other_income_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "allowance_amount_positive", + "CHECK(allowance_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "benefits_in_kind_amount_positive", + "CHECK(benefits_in_kind_amount >= 0)", + "Negative amounts not allowed!", + ), + ( + "withholding_tax_amount_positive", + "CHECK(withholding_tax_amount >= 0)", + "Negative amounts not allowed!", + ), + ] + + @api.depends( + "parent_id.partner_declare_threshold", + "fee_amount", + "commission_amount", + "brokerage_amount", + "discount_amount", + "attendance_fee_amount", + "copyright_royalties_amount", + "licence_royalties_amount", + "other_income_amount", + "allowance_amount", + "benefits_in_kind_amount", + "withholding_tax_amount", + ) + def _compute_total_amount(self): + for line in self: + total_amount = 0 + for field_name in AMOUNT_FIELDS: + total_amount += line[field_name] + to_declare = False + if line.parent_id: + if total_amount >= line.parent_id.partner_declare_threshold: + to_declare = True + line.to_declare = to_declare + line.total_amount = total_amount + + @api.depends("partner_id") + def _compute_partner_siret(self): + for line in self: + if line.partner_id and line.partner_id.siren and line.partner_id.nic: + line.partner_siret = line.partner_id.siret + + @api.depends("partner_id") + def _compute_job(self): + for line in self: + if line.partner_id and line.partner_id.fr_das2_job: + line.job = line.partner_id.fr_das2_job + + @api.constrains("partner_siret") + def check_siret(self): + for line in self: + if line.partner_siret and not is_valid(line.partner_siret): + raise ValidationError(_("SIRET '%s' is invalid.") % line.partner_siret) diff --git a/l10n_fr_das2/models/res_company.py b/l10n_fr_das2/models/res_company.py new file mode 100644 index 0000000000..dc55313aaa --- /dev/null +++ b/l10n_fr_das2/models/res_company.py @@ -0,0 +1,21 @@ +# Copyright 2020-2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + fr_das2_partner_declare_threshold = fields.Integer( + string="DAS2 Partner Declaration Threshold", default=1200 + ) + + _sql_constraints = [ + ( + "fr_das2_partner_declare_threshold_positive", + "CHECK(fr_das2_partner_declare_threshold >= 0)", + "The DAS2 partner declaration threshold must be positive!", + ) + ] diff --git a/l10n_fr_das2/models/res_partner.py b/l10n_fr_das2/models/res_partner.py new file mode 100644 index 0000000000..3679c93f9d --- /dev/null +++ b/l10n_fr_das2/models/res_partner.py @@ -0,0 +1,28 @@ +# Copyright 2020-2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + fr_das2_type = fields.Selection( + [ + ("fee", "Honoraires et vacations"), + ("commission", "Commissions"), + ("brokerage", "Courtages"), + ("discount", "Ristournes"), + ("attendance_fee", "Jetons de présence"), + ("copyright_royalties", "Droits d'auteur"), + ("licence_royalties", "Droits d'inventeur"), + ("other_income", "Autre rémunérations"), + ("allowance", "Indemnités et remboursements"), + ], + string="DAS2 Type", + tracking=100, + ) + fr_das2_job = fields.Char( + string="DAS2 Job", size=30, help="Used in the field 'Profession' of DAS2." + ) diff --git a/l10n_fr_das2/readme/CONFIGURE.rst b/l10n_fr_das2/readme/CONFIGURE.rst new file mode 100644 index 0000000000..89a6765e78 --- /dev/null +++ b/l10n_fr_das2/readme/CONFIGURE.rst @@ -0,0 +1,18 @@ +On the supplier form view, in the *Accounting* tab, you will see a section *DAS2*. For the suppliers that must be declared in DAS2, you must set: + +* the DAS2 Type, +* the job for the DAS2 declaration, +* their SIRET number (for French suppliers only), +* their full address (street, zip code, city and country). + +On the company configuration form, the APE code, SIRET and address must be set. + +For the user responsible for the declaration, the phone number and email must be set on his related partner form (name, email and phone number are used in the DAS2 declaration file). + +If you want to encrypt the declaration file with the DGFiP's **test** PGP key, ensure that your Odoo server configuration file has the following parameter: + +.. code:: + + running_env = test + +Otherwise, Odoo will use DGFiP's **production** PGP key. diff --git a/l10n_fr_das2/readme/CONTRIBUTORS.rst b/l10n_fr_das2/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..ff65d68ce6 --- /dev/null +++ b/l10n_fr_das2/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/l10n_fr_das2/readme/DESCRIPTION.rst b/l10n_fr_das2/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..4694012bda --- /dev/null +++ b/l10n_fr_das2/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module adds support for `DAS2 _`, which is an annual fiscal declaration also called *Déclaration d'honoraires*. It will allow you to auto-generate the lines of DAS2 from the accounting entries, check the result, manually update lines if needed and eventually generate a declaration file. Then send the declaration file to the French tax office via your professional account on *impots.gouv.fr* + +The specifications of the file are available on `this page `_. diff --git a/l10n_fr_das2/readme/INSTALL.rst b/l10n_fr_das2/readme/INSTALL.rst new file mode 100644 index 0000000000..a6208db8ab --- /dev/null +++ b/l10n_fr_das2/readme/INSTALL.rst @@ -0,0 +1,7 @@ +This module requires the Python lib `pyfrdas2 `_. As this lib contains the PGP encryption keys of the DGFiP used to encrypt the declaration file and as these keys are changed every year, check that the lib is up-to-date before using the module for a new year. + +To install this lib, run: + +.. code:: + + pip3 install --upgrade pyfrdas2 diff --git a/l10n_fr_das2/readme/USAGE.rst b/l10n_fr_das2/readme/USAGE.rst new file mode 100644 index 0000000000..a1ef0b7670 --- /dev/null +++ b/l10n_fr_das2/readme/USAGE.rst @@ -0,0 +1,9 @@ +Go to the menu *Accounting > Reports > French Statements > DAS2* and create a new DAS2 report. + +Then click on the button *Generate Lines*. Check and edit the generated lines. You can get the details of the computation performed by Odoo in the *Note* fields of each line. + +You may have a yellow warning banner that warn you about suppliers that have expenses recorded in accounts such as 622100 Commissions et courtages sur achats, 622200 Commissions et courtages sur ventes, 622600 Honoraires, 622800 Rémunérations d'intermédiaires divers, 653000 Jetons de présence, 651600 Droits d'auteur et de reproduction that are not configured for DAS2. + +Once your declaration is OK, click on the button *Done*: it will generate the DAS2 file and set the declaration to *Done* state (all the fields become readonly). + +To send the file to the French tax office, go to your professional account on `impots.gouv.fr `_, go to the menu **Déclarer > Tiers déclarant** and then click on the button **Déposer un fichier**. Select **Salaires et/ou honoraires** and follow the instructions. diff --git a/l10n_fr_das2/security/das2_security.xml b/l10n_fr_das2/security/das2_security.xml new file mode 100644 index 0000000000..88c12ddf2b --- /dev/null +++ b/l10n_fr_das2/security/das2_security.xml @@ -0,0 +1,19 @@ + + + + + + DAS2 multi-company + + [('company_id', 'in', company_ids)] + + + + + DAS2 Line multi-company + + [('company_id', 'in', company_ids)] + + + + diff --git a/l10n_fr_das2/security/ir.model.access.csv b/l10n_fr_das2/security/ir.model.access.csv new file mode 100644 index 0000000000..6601efbb36 --- /dev/null +++ b/l10n_fr_das2/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_l10n_fr_das2,Full access to l10n.fr.das2 to accountant,model_l10n_fr_das2,account.group_account_user,1,1,1,1 +access_l10n_fr_das2_line,Full access to l10n.fr.das2.line to accoutant,model_l10n_fr_das2_line,account.group_account_user,1,1,1,1 diff --git a/l10n_fr_das2/static/description/icon.png b/l10n_fr_das2/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/l10n_fr_das2/static/description/icon.png differ diff --git a/l10n_fr_das2/static/description/index.html b/l10n_fr_das2/static/description/index.html new file mode 100644 index 0000000000..4f4222b139 --- /dev/null +++ b/l10n_fr_das2/static/description/index.html @@ -0,0 +1,494 @@ + + + + + + +DAS2 + + + +
      +

      DAS2

      + + +

      Beta License: AGPL-3 OCA/l10n-france Translate me on Weblate Try me on Runbot

      +

      This module adds support for DAS2 <https://www.impots.gouv.fr/portail/formulaire/das2/etat-des-honoraires-vacations-commissions-courtages-ristournes-et-jetons>_, which is an annual fiscal declaration also called Déclaration d’honoraires. It will allow you to auto-generate the lines of DAS2 from the accounting entries, check the result, manually update lines if needed and eventually generate a declaration file. Then send the declaration file to the French tax office via your professional account on impots.gouv.fr

      +

      The specifications of the file are available on this page.

      +

      Table of contents

      +
      +
      +
      +

      Installation

      +

      This module requires the Python lib pyfrdas2. As this lib contains the PGP encryption keys of the DGFiP used to encrypt the declaration file and as these keys are changed every year, check that the lib is up-to-date before using the module for a new year.

      +

      To install this lib, run:

      +
      +pip3 install --upgrade pyfrdas2
      +
      +
      +
      +<<<<<<< HEAD +

      Configuration

      +======= +

      Configuration

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) +

      On the supplier form view, in the Accounting tab, you will see a section DAS2. For the suppliers that must be declared in DAS2, you must set:

      +
        +
      • the DAS2 Type,
      • +
      • the job for the DAS2 declaration,
      • +
      • their SIRET number (for French suppliers only),
      • +
      • their full address (street, zip code, city and country).
      • +
      +

      On the company configuration form, the APE code, SIRET and address must be set.

      +

      For the user responsible for the declaration, the phone number and email must be set on his related partner form (name, email and phone number are used in the DAS2 declaration file).

      +
      +
      +<<<<<<< HEAD +

      Usage

      +======= +

      Usage

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) +

      Go to the menu Accounting > Reports > French Statements > DAS2 and create a new DAS2 report.

      +

      Then click on the button Generate Lines. Check and edit the generated lines. You can get the details of the computation performed by Odoo in the Note fields of each line.

      +

      You may have a yellow warning banner that warn you about suppliers that have expenses recorded in accounts such as 622100 Commissions et courtages sur achats, 622200 Commissions et courtages sur ventes, 622600 Honoraires, 622800 Rémunérations d’intermédiaires divers, 653000 Jetons de présence, 651600 Droits d’auteur et de reproduction that are not configured for DAS2.

      +

      Once your declaration is OK, click on the button Done: it will generate the DAS2 file and set the declaration to Done state (all the fields become readonly).

      +

      To send the file to the French tax office, go to your professional account on impots.gouv.fr, go to the menu Déclarer > Tiers déclarant and then click on the button Déposer un fichier. Select Salaires et/ou honoraires and follow the instructions.

      +
      +
      +<<<<<<< HEAD +

      Bug Tracker

      +======= +

      Bug Tracker

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) +

      Bugs are tracked on GitHub 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.

      +

      Do not contact contributors directly about support or help with technical issues.

      +
      +
      +<<<<<<< HEAD +

      Credits

      +
      +

      Authors

      +======= +

      Credits

      +
      +

      Authors

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) +
        +
      • Akretion
      • +
      +
      +
      +<<<<<<< HEAD +

      Contributors

      +======= +

      Contributors

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) + +
      +
      +<<<<<<< HEAD +

      Maintainers

      +======= +

      Maintainers

      +>>>>>>> 7ffd40ba (l10n_fr_das2: update for millesime 2024 using pyfrdas2) +

      This module is maintained by the OCA.

      +Odoo Community Association +

      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.

      +

      Current maintainer:

      +

      alexis-via

      +

      This module is part of the OCA/l10n-france project on GitHub.

      +

      You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

      +
      +
      +
      + + diff --git a/l10n_fr_das2/tests/__init__.py b/l10n_fr_das2/tests/__init__.py new file mode 100644 index 0000000000..26e0d6fddd --- /dev/null +++ b/l10n_fr_das2/tests/__init__.py @@ -0,0 +1 @@ +from . import test_das2 diff --git a/l10n_fr_das2/tests/test_das2.py b/l10n_fr_das2/tests/test_das2.py new file mode 100644 index 0000000000..d374f808fa --- /dev/null +++ b/l10n_fr_das2/tests/test_das2.py @@ -0,0 +1,94 @@ +# Copyright 2024 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestFrDas2(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env["res.company"].create( + { + "name": "Test company DAS2", + "street": "42, rue de la paix", + "zip": "69100", + "city": "Villeurbanne", + "country_id": cls.env.ref("base.fr").id, + "currency_id": cls.env.ref("base.EUR").id, + "siren": "792377731", + "nic": "00023", + "ape": "6202Z", + } + ) + cls.env.user.phone = "+33742124212" + cls.partner1 = cls.env["res.partner"].create( + { + "is_company": True, + "name": "Mon expert comptable préféré", + "street": "42 rue du chiffre", + "zip": "69009", + "city": "Lyon", + "country_id": cls.env.ref("base.fr").id, + "email": "experts@comptables.example.com", + "fr_das2_type": "fee", + "fr_das2_job": "Expert comptable", + "siren": "555555556", + "nic": "00011", + } + ) + cls.partner2 = cls.env["res.partner"].create( + { + "is_company": True, + "name": "Mon avocat", + "street": "12 rue du tribunal", + "zip": "69009", + "city": "Lyon", + "country_id": cls.env.ref("base.fr").id, + "email": "avocat@example.com", + "fr_das2_type": "fee", + "fr_das2_job": "Avocat", + "siren": "666666664", + "nic": "00014", + } + ) + + def test_das2(self): + decl = self.env["l10n.fr.das2"].create( + { + "year": 2023, + "company_id": self.company.id, + "payment_journal_ids": [], + } + ) + self.assertEqual(self.partner1.siret, "55555555600011") + self.env["l10n.fr.das2.line"].create( + { + "partner_id": self.partner1.id, + "parent_id": decl.id, + "fee_amount": 2000, + } + ) + self.env["l10n.fr.das2.line"].create( + { + "partner_id": self.partner2.id, + "parent_id": decl.id, + "fee_amount": 3123, + } + ) + self.assertEqual(decl.state, "draft") + decl.done() + self.assertEqual(decl.state, "done") + self.assertTrue(decl.attachment_id) + self.assertTrue( + decl.attachment_id.name.startswith( + f"DSAL_{decl.year}_{decl.company_id.siren}_000_" + ) + ) + self.assertTrue(decl.attachment_id.name.endswith(".txt.gz.gpg")) + self.assertTrue(decl.unencrypted_attachment_id) + self.assertTrue(decl.unencrypted_attachment_id.name.endswith(".txt")) diff --git a/l10n_fr_das2/views/l10n_fr_das2.xml b/l10n_fr_das2/views/l10n_fr_das2.xml new file mode 100644 index 0000000000..a518cfe2d8 --- /dev/null +++ b/l10n_fr_das2/views/l10n_fr_das2.xml @@ -0,0 +1,260 @@ + + + + + + + l10n.fr.das2.form + l10n.fr.das2 + +
      +
      +
      + + +
      + +
      + + + + + + + + + + + + + + + + + + + +
      +
      + + + +
      +
      +
      +
      + + + + l10n.fr.das2.tree + l10n.fr.das2 + + + + + + + + + + + + l10n.fr.das2.search + l10n.fr.das2 + + + + + + + + + + + DAS2 + l10n.fr.das2 + tree,form + + + + + + + l10n.fr.das2.line.form + l10n.fr.das2.line + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      + + + l10n.fr.das2.line.tree + l10n.fr.das2.line + + + + + + + + + + + + + + + + + + + + + + + + + l10n.fr.das2.line.search + l10n.fr.das2.line + + + + + + + + + + + + DAS2 Lines + l10n.fr.das2.line + tree,form + + + +
      diff --git a/l10n_fr_das2/views/res_config_settings.xml b/l10n_fr_das2/views/res_config_settings.xml new file mode 100644 index 0000000000..c916d7026c --- /dev/null +++ b/l10n_fr_das2/views/res_config_settings.xml @@ -0,0 +1,36 @@ + + + + + + + das2.res.config.settings.form + res.config.settings + + + +

      DAS2

      +
      +
      +
      +
      +
      +
      +
      +
      +
      + + + + + + diff --git a/l10n_fr_das2/views/res_partner.xml b/l10n_fr_das2/views/res_partner.xml new file mode 100644 index 0000000000..c2573021a7 --- /dev/null +++ b/l10n_fr_das2/views/res_partner.xml @@ -0,0 +1,42 @@ + + + + + + + l10n.fr.das2.res.partner.form + res.partner + + + + + + + + + + + + + l10n.fr.das2.res.partner.search + res.partner + + + + + + + + + + + + diff --git a/l10n_fr_das2/wizards/__init__.py b/l10n_fr_das2/wizards/__init__.py new file mode 100644 index 0000000000..0deb68c468 --- /dev/null +++ b/l10n_fr_das2/wizards/__init__.py @@ -0,0 +1 @@ +from . import res_config_settings diff --git a/l10n_fr_das2/wizards/res_config_settings.py b/l10n_fr_das2/wizards/res_config_settings.py new file mode 100644 index 0000000000..ff3f48b84d --- /dev/null +++ b/l10n_fr_das2/wizards/res_config_settings.py @@ -0,0 +1,13 @@ +# Copyright 2020-2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + fr_das2_partner_declare_threshold = fields.Integer( + related="company_id.fr_das2_partner_declare_threshold", readonly=False + ) diff --git a/requirements.txt b/requirements.txt index b59013820e..0230dee4cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ # generated from manifests external_dependencies +pyfrdas2 +python-stdnum python-stdnum>=1.18 requests_oauthlib unidecode diff --git a/setup/l10n_fr_cog/odoo/addons/l10n_fr_cog b/setup/l10n_fr_cog/odoo/addons/l10n_fr_cog new file mode 120000 index 0000000000..7c3200b326 --- /dev/null +++ b/setup/l10n_fr_cog/odoo/addons/l10n_fr_cog @@ -0,0 +1 @@ +../../../../l10n_fr_cog \ No newline at end of file diff --git a/setup/l10n_fr_cog/setup.py b/setup/l10n_fr_cog/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/l10n_fr_cog/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/l10n_fr_das2/odoo/addons/l10n_fr_das2 b/setup/l10n_fr_das2/odoo/addons/l10n_fr_das2 new file mode 120000 index 0000000000..c023e85546 --- /dev/null +++ b/setup/l10n_fr_das2/odoo/addons/l10n_fr_das2 @@ -0,0 +1 @@ +../../../../l10n_fr_das2 \ No newline at end of file diff --git a/setup/l10n_fr_das2/setup.py b/setup/l10n_fr_das2/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/l10n_fr_das2/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)