diff --git a/account_analytic_distribution_model_recalculate/README.rst b/account_analytic_distribution_model_recalculate/README.rst new file mode 100644 index 0000000000..5bcf9b4db7 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/README.rst @@ -0,0 +1,144 @@ +=============================================== +Account Analytic Distribution Model Recalculate +=============================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:814b6566780ac734313e0b819b5e79fab90268cf7365ea4be8f81f182148f9c6 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Faccount--analytic-lightgray.png?logo=github + :target: https://github.com/OCA/account-analytic/tree/16.0/account_analytic_distribution_model_recalculate + :alt: OCA/account-analytic +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-analytic-16-0/account-analytic-16-0-account_analytic_distribution_model_recalculate + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-analytic&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to regenerate the analytic distribution of the +journal items, that were generated by the distribution model. + +It adds the posibility to add a Start Date and End Date for the +distribution models too. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. **Navigate to Analytic Distribution Models** + +- Go to Invoicing -> Configuration -> Analytic Distribution Models. + +2. **Create or Edit a Distribution Model** + +- Create a new distribution model or edit an existing one. +- Set the **Start Date** and **End Date** to define the active period + for the distribution. Only distributions within this date range will + be applied. +- Define filters such as **Partner** and **Account Prefix** to control + when the model should apply. + +3. **Create an Invoice or Vendor Bill** + +- Select a customer and an account that match the conditions set in the + distribution model. +- If the invoice has a date, the system will use it to filter + applicable distribution models; otherwise, it will use the current + date. + +4. **Use the Recalculate Function** + +- Go to **Analytic Distribution Models**. +- Enable the **Recalculate** option on the model you want to update. +- Modify the analytic distribution as needed. +- Click the **Recalculate** button. (Partner and account prefix needs + to be set) +- All journal items originally updated using this model, and still + within its date range and matching its criteria, will be + recalculated, using the current distribution of the model. + +**Sync Distribution Models with Journal Items** +----------------------------------------------- + +You can use the **Sync** button to associate all journal items that +match the distribution model's criteria. + +This is especially useful in the following cases: + +- Journal items were created **before** the distribution model existed. +- The model has been **updated or changed**, and you want to reassign + journal items accordingly. +- You need to **sync lines** from other entries that now match the + model's conditions. + +By syncing, the system will disassociate any previous links and reassign +journal items based on the current configuration of the distribution +model. + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* APSL-Nagarro +* Bernat Obrador + +Contributors +------------ + +- APSL - Nagarro + + - Bernat Obrador + +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-BernatObrador| image:: https://github.com/BernatObrador.png?size=40px + :target: https://github.com/BernatObrador + :alt: BernatObrador + +Current `maintainer `__: + +|maintainer-BernatObrador| + +This module is part of the `OCA/account-analytic `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_analytic_distribution_model_recalculate/__init__.py b/account_analytic_distribution_model_recalculate/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/account_analytic_distribution_model_recalculate/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_analytic_distribution_model_recalculate/__manifest__.py b/account_analytic_distribution_model_recalculate/__manifest__.py new file mode 100644 index 0000000000..025cbc5a59 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2024 (APSL-Nagarro) - Bernat Obrador +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Account Analytic Distribution Model Recalculate", + "summary": """Add the posibility to change the analytic distribution of the journal + items assigned by the distribution model""", + "version": "16.0.1.0.1", + "license": "AGPL-3", + "author": "Odoo Community Association (OCA), APSL-Nagarro, Bernat Obrador", + "website": "https://github.com/OCA/account-analytic", + "maintainers": ["BernatObrador"], + "depends": [ + "account", + "analytic", + ], + "data": [ + "views/account_analytic_distribution_model.xml", + "views/account_move_line.xml", + ], + "installable": True, + "application": False, +} diff --git a/account_analytic_distribution_model_recalculate/i18n/account_analytic_distribution_model_recalculate.pot b/account_analytic_distribution_model_recalculate/i18n/account_analytic_distribution_model_recalculate.pot new file mode 100644 index 0000000000..91e4ec9453 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/i18n/account_analytic_distribution_model_recalculate.pot @@ -0,0 +1,117 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_analytic_distribution_model_recalculate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.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: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "%s analytic lines have been recalculated." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_analytic_distribution_model +msgid "Analytic Distribution Model" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Cannot have overlapping dates for the same partner and account prefix." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_move_line__distribution_model_id +msgid "Distribution Model" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__end_date +msgid "End Date" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_form_view +msgid "Filter Dates" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,help:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +msgid "" +"If checked, you will be able to recalculate\n" +" the analytic lines that where created by this model,\n" +" and still matches the model criteria" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "No analytic lines have been recalculated." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Recalculate" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.actions.server,name:account_analytic_distribution_model_recalculate.action_recalculate_analytic_distribution +msgid "Recalculate Analytic Lines" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Recalculation Complete" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__start_date +msgid "Start Date" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Sync" +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "" +"Sync the journal items with the analytic distribution model. Used to sync " +"lines that were generated before the model was created." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "The start date cannot be later than the end date." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "You must select a partner and account prefix to recalculate lines." +msgstr "" diff --git a/account_analytic_distribution_model_recalculate/i18n/ca.po b/account_analytic_distribution_model_recalculate/i18n/ca.po new file mode 100644 index 0000000000..4f4f30af04 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/i18n/ca.po @@ -0,0 +1,134 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_analytic_distribution_model_recalculate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-06-10 13:18+0000\n" +"PO-Revision-Date: 2025-06-10 13:18+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "%s analytic lines have been recalculated." +msgstr "S'han recalculat %s línies analítiques." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_analytic_distribution_model +msgid "Analytic Distribution Model" +msgstr "Model de distribució analític" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Cannot have overlapping dates for the same partner and account prefix." +msgstr "" +"No es poden tenir dates que es sobreposin per al mateix contacte i prefix de " +"compte." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_move_line__distribution_model_id +msgid "Distribution Model" +msgstr "Model de Distribució" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__end_date +msgid "End Date" +msgstr "Data de Final" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_form_view +msgid "Filter Dates" +msgstr "Dates de Filtratge" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,help:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +msgid "" +"If checked, you will be able to recalculate\n" +" the analytic lines that where created by this model,\n" +" and still matches the model criteria" +msgstr "" +"Si està activat, podràs recalcular les línies analítiques que han estat " +"creades per aquest model i que encara compleixen els criteris del model." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_move_line +msgid "Journal Item" +msgstr "Apunt comptable" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "No analytic lines have been recalculated." +msgstr "No s'han recalculat línies analítiques." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Recalculate" +msgstr "Recalcular" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.actions.server,name:account_analytic_distribution_model_recalculate.action_recalculate_analytic_distribution +msgid "Recalculate Analytic Lines" +msgstr "Recalcular línies analítiques" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Recalculation Complete" +msgstr "Recalculació completada" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__start_date +msgid "Start Date" +msgstr "Data d'Inici" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Sync" +msgstr "Sincronitzar" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "" +"Sync the journal items with the analytic distribution model. Used to sync " +"lines that were generated before the model was created." +msgstr "" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "The start date cannot be later than the end date." +msgstr "La data d'inici no pot ser posterior a la data de finalització." + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "You must select a partner and account prefix to recalculate lines." +msgstr "" +"Has de seleccionar un contacte i un prefix de compte per recalcular les " +"línies." + +#~ msgid "" +#~ "Sync the journal items with the analytic distribution model. Used to sync " +#~ "lines that where generated before the model was created." +#~ msgstr "" +#~ "Sincronitza els elements del diari amb el model de distribució analítica. " +#~ "S'utilitza per sincronitzar les línies que es van generar abans de la " +#~ "creació del model." diff --git a/account_analytic_distribution_model_recalculate/i18n/es.po b/account_analytic_distribution_model_recalculate/i18n/es.po new file mode 100644 index 0000000000..50dcfb6f18 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/i18n/es.po @@ -0,0 +1,129 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_analytic_distribution_model_recalculate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-06-10 13:15+0000\n" +"PO-Revision-Date: 2025-06-10 13:15+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "%s analytic lines have been recalculated." +msgstr "Se han recalculado %s líneas analíticas." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_analytic_distribution_model +msgid "Analytic Distribution Model" +msgstr "Modelo de distribución analítica" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Cannot have overlapping dates for the same partner and account prefix." +msgstr "" +"No se pueden tener fechas superpuestas para el mismo contacto y prefijo de " +"cuenta." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_move_line__distribution_model_id +msgid "Distribution Model" +msgstr "Modelo de Distribución" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__end_date +msgid "End Date" +msgstr "Fecha Final" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_form_view +msgid "Filter Dates" +msgstr "Fechas de Filtrado" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,help:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +msgid "" +"If checked, you will be able to recalculate\n" +" the analytic lines that where created by this model,\n" +" and still matches the model criteria" +msgstr "" +"Si está activado, podrás recalcular las líneas analíticas que fueron creadas " +"por este modelo y que aún cumplen con los criterios del mismo." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_move_line +msgid "Journal Item" +msgstr "Apunte contable" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "No analytic lines have been recalculated." +msgstr "No se han recalculado líneas analíticas." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Recalculate" +msgstr "Recalcular" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.actions.server,name:account_analytic_distribution_model_recalculate.action_recalculate_analytic_distribution +msgid "Recalculate Analytic Lines" +msgstr "Recalcular líneas analíticas" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Recalculation Complete" +msgstr "Recalculación completada" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__start_date +msgid "Start Date" +msgstr "Fecha de Inicio" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Sync" +msgstr "Sincronizar" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "" +"Sync the journal items with the analytic distribution model. Used to sync " +"lines that were generated before the model was created." +msgstr "" +"Sincronizar los elementos del diario con el modelo de distribución " +"analítica. Se utiliza para sincronizar las líneas generadas antes de la " +"creación del modelo." + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "The start date cannot be later than the end date." +msgstr "La fecha de inicio no puede ser posterior a la fecha de finalización." + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "You must select a partner and account prefix to recalculate lines." +msgstr "" +"Debe seleccionar un contacto y un prefijo de cuenta para recalcular las " +"líneas." diff --git a/account_analytic_distribution_model_recalculate/i18n/it.po b/account_analytic_distribution_model_recalculate/i18n/it.po new file mode 100644 index 0000000000..0c19974621 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/i18n/it.po @@ -0,0 +1,129 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_analytic_distribution_model_recalculate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-06-17 08:26+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\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 5.10.4\n" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "%s analytic lines have been recalculated." +msgstr "Sono state ricalcolate %s righe analitiche." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_analytic_distribution_model +msgid "Analytic Distribution Model" +msgstr "Modello distribuzione analitica" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Cannot have overlapping dates for the same partner and account prefix." +msgstr "" +"Non si possono avere date sovrapposte per lo stesso partner e prefisso del " +"conto." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_move_line__distribution_model_id +msgid "Distribution Model" +msgstr "Modello distribuzione" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__end_date +msgid "End Date" +msgstr "Data fine" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_form_view +msgid "Filter Dates" +msgstr "Date filtro" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,help:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +msgid "" +"If checked, you will be able to recalculate\n" +" the analytic lines that where created by this model,\n" +" and still matches the model criteria" +msgstr "" +"Se selezionata si potranno ricalcolare\n" +" le righe analitiche che sono state create da questo modello\n" +" e che corrispondono ali criteri del modello" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model,name:account_analytic_distribution_model_recalculate.model_account_move_line +msgid "Journal Item" +msgstr "Movimento contabile" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "No analytic lines have been recalculated." +msgstr "Nessuna riga analitica è stata ricalcolata." + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Recalculate" +msgstr "Ricalcolo" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.actions.server,name:account_analytic_distribution_model_recalculate.action_recalculate_analytic_distribution +msgid "Recalculate Analytic Lines" +msgstr "Ricalcolo righe analitiche" + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "Recalculation Complete" +msgstr "Ricalcolo completo" + +#. module: account_analytic_distribution_model_recalculate +#: model:ir.model.fields,field_description:account_analytic_distribution_model_recalculate.field_account_analytic_distribution_model__start_date +msgid "Start Date" +msgstr "Data inizio" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "Sync" +msgstr "Sincronizza" + +#. module: account_analytic_distribution_model_recalculate +#: model_terms:ir.ui.view,arch_db:account_analytic_distribution_model_recalculate.inherit_account_analytic_distribution_model_tree_view +msgid "" +"Sync the journal items with the analytic distribution model. Used to sync " +"lines that were generated before the model was created." +msgstr "" +"Sincronizza le registrazioni contabili con il modello distribuzione " +"analitica. Usato per sincronizzare le righe che sono state generate prima " +"della creazione del modello." + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "The start date cannot be later than the end date." +msgstr "La data di inizio non può essere successiva alla data di fine." + +#. module: account_analytic_distribution_model_recalculate +#. odoo-python +#: code:addons/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py:0 +#, python-format +msgid "You must select a partner and account prefix to recalculate lines." +msgstr "" +"Bisogna selezionare un partner e prefisso del conto per ricalcolare le righe." diff --git a/account_analytic_distribution_model_recalculate/models/__init__.py b/account_analytic_distribution_model_recalculate/models/__init__.py new file mode 100644 index 0000000000..4a72a3607f --- /dev/null +++ b/account_analytic_distribution_model_recalculate/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_analytic_distribution_model +from . import account_move_line diff --git a/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py b/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py new file mode 100644 index 0000000000..07d83bdb31 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/models/account_analytic_distribution_model.py @@ -0,0 +1,266 @@ +# Copyright 2024 (APSL - Nagarro) Bernat Obrador +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + +from odoo.addons.analytic.models.analytic_distribution_model import ( + NonMatchingDistribution, +) + + +class AccountAnalyticDistributionModel(models.Model): + _inherit = ["account.analytic.distribution.model"] + + start_date = fields.Date() + end_date = fields.Date() + recalculate = fields.Boolean( + help="""If checked, you will be able to recalculate + the analytic lines that where created by this model, + and still matches the model criteria""", + default=False, + ) + + def _compute_display_name(self): + for model in self: + parts = [] + + if model.account_prefix: + parts.append(model.account_prefix) + + if model.partner_id: + parts.append(model.partner_id.name) + + if model.partner_category_id: + parts.append(model.partner_category_id.name) + + if model.product_id: + parts.append(model.product_id.display_name) + + if model.product_categ_id: + parts.append(model.product_categ_id.name) + + main_info = " | ".join(parts) + + start_date = ( + model.start_date.strftime("%Y-%m-%d") if model.start_date else "" + ) + end_date = model.end_date.strftime("%Y-%m-%d") if model.end_date else "" + + date_info = f"{start_date} - {end_date}" if start_date or end_date else "" + + model.display_name = f"{main_info} ({date_info})" + + @api.constrains("start_date", "end_date") + def _check_start_date_before_end_date(self): + for record in self: + if ( + record.start_date + and record.end_date + and record.start_date > record.end_date + ): + raise ValidationError( + _("The start date cannot be later than the end date.") + ) + + @api.model + def _get_distribution(self, vals): + """ + Override the _get_distribution method to add the distribution_model_id + to the result. + """ + if self.env.context.get("get_distributiion_model_id"): + domain = [] + for fname, value in vals.items(): + domain += self._create_domain(fname, value) or [] + best_score = 0 + res = {} + fnames = set(self._get_fields_to_check()) + for rec in self.search(domain): + try: + score = sum(rec._check_score(key, vals.get(key)) for key in fnames) + if score > best_score: + res = rec + best_score = score + except NonMatchingDistribution: + continue + return res + else: + return super()._get_distribution(vals) + + def _get_fields_to_check(self): + # Exclude the recalculate field from the fields to check + # to avoid NonMatchingDistribution + return [f for f in super()._get_fields_to_check() if f != "recalculate"] + + def _check_score(self, key, value): + self.ensure_one() + if key == "start_date" or key == "end_date": + return 1 + + return super()._check_score(key, value) + + def _create_domain(self, fname, value): + if fname == "date" and value: + return [ + "|", + "&", + ("start_date", "<=", value), + ("end_date", ">=", value), + "|", + "&", + ("start_date", "<=", value), + ("end_date", "=", False), + "|", + "&", + ("start_date", "=", False), + ("end_date", ">=", value), + "&", + ("start_date", "=", False), + ("end_date", "=", False), + ] + return super()._create_domain(fname, value) + + def _get_domain(self): + self.ensure_one() + + def safe(field, operator, value): + return (field, operator, value) if value else None + + domain = list( + filter( + None, + [ + safe("partner_id", "=", self.partner_id.id), + safe("company_id", "=", self.company_id.id), + safe("product_id", "=", self.product_id.id), + safe("product_categ_id", "=", self.product_categ_id.id), + safe("partner_category_id", "=", self.partner_category_id.id), + ( + safe("account_prefix", "=ilike", f"{self.account_prefix}%") + if self.account_prefix + else ("account_prefix", "=", False) + ), + ], + ) + ) + + if self.start_date and self.end_date: + domain += [ + "&", + ("start_date", "<=", self.end_date), + ("end_date", ">=", self.start_date), + ] + elif self.start_date: + domain.append(("end_date", ">=", self.start_date)) + elif self.end_date: + domain.append(("start_date", "<=", self.end_date)) + + return domain + + def _get_message(self, updated_lines): + return ( + _("%s analytic lines have been recalculated.") % updated_lines + if updated_lines + else _("No analytic lines have been recalculated.") + ) + + def _get_lines_domain(self): + self.ensure_one() + + def _add_condition(domain, field, operator, value): + if value: + domain.append((field, operator, value.id)) + + if not self.recalculate: + pass + + if not self.account_prefix or not self.partner_id: + # To avoid massive recalculation of all lines just + # recalculate the lines that has the same partner and account prefix + raise ValidationError( + _( + "You must select a partner and account prefix " + "to recalculate lines." + ) + ) + + domain = [] + + start_date = self.start_date + end_date = self.end_date + + if start_date and end_date: + domain += [ + "&", + ("date", "<=", end_date), + ("date", ">=", start_date), + ] + elif start_date: + domain.append(("date", ">=", start_date)) + elif end_date: + domain.append(("date", "<=", end_date)) + + if self.account_prefix: + domain.append(("account_id.code", "=ilike", f"{self.account_prefix}%")) + + _add_condition(domain, "partner_id", "=", self.partner_id) + _add_condition(domain, "partner_id.category_id", "=", self.partner_category_id) + _add_condition(domain, "product_id.categ_id", "=", self.product_categ_id) + _add_condition(domain, "product_id", "=", self.product_id) + + return domain + + def action_recalculate_analytic_lines(self): + """ + Recalculate the analytic lines that match the distribution model + and where generated by himself. + """ + + for record in self: + domain = record._get_lines_domain() + domain.append(("distribution_model_id", "=", record.id)) + + domain.append(("analytic_distribution", "!=", record.analytic_distribution)) + + lines_to_update = self.env["account.move.line"].search(domain) + + if lines_to_update: + lines_to_update.write( + {"analytic_distribution": record.analytic_distribution} + ) + + message = self._get_message(len(lines_to_update)) + + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": _("Recalculation Complete"), + "message": message, + "type": "success", + "sticky": False, + }, + } + + def action_sync_lines(self): + """ + Sync the jorurnal items that match the distribution model + """ + + for record in self: + actual_lines = self.env["account.move.line"].search( + [ + ("distribution_model_id", "=", record.id), + ] + ) + actual_lines.write({"distribution_model_id": False}) + + domain = record._get_lines_domain() + lines = self.env["account.move.line"].search(domain) + + lines.write( + { + "distribution_model_id": record.id, + } + ) diff --git a/account_analytic_distribution_model_recalculate/models/account_move_line.py b/account_analytic_distribution_model_recalculate/models/account_move_line.py new file mode 100644 index 0000000000..f816920a93 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/models/account_move_line.py @@ -0,0 +1,88 @@ +# Copyright 2024 (APSL - Nagarro) Bernat Obrador +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class AccountMoveLine(models.Model): + _inherit = ["account.move.line"] + + distribution_model_id = fields.Many2one( + "account.analytic.distribution.model", + string="Distribution Model", + ) + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + for line in res: + line._get_distribution_id() + return res + + def write(self, vals): + res = super().write(vals) + if vals.get("account_id") or vals.get("partner_id") or vals.get("product_id"): + for line in self: + line._get_distribution_id() + return res + + @api.depends("account_id", "partner_id", "product_id") + def _compute_analytic_distribution(self): + cache = {} + + for line in self: + if line.display_type == "product" or not line.move_id.is_invoice( + include_receipts=True + ): + args = { + "product_id": line.product_id.id, + "product_categ_id": line.product_id.categ_id.id, + "partner_id": line.partner_id.id, + "partner_category_id": line.partner_id.category_id.ids, + "account_prefix": line.account_id.code, + "company_id": line.company_id.id, + "date": self._get_date(line).strftime("%Y-%m-%d"), + } + + key = tuple( + sorted( + (k, tuple(v) if isinstance(v, list) else v) + for k, v in args.items() + ) + ) + + if key not in cache: + cache[key] = self.env[ + "account.analytic.distribution.model" + ]._get_distribution(args) + + line.analytic_distribution = cache[key] or line.analytic_distribution + + def _get_date(self, line): + move = line.move_id + return move.invoice_date or move.date or fields.Date.today() + + def _get_distribution_id(self): + """ + Function to assign from wich distribution model we get the + analytic distribution. + It's needed, because in _compute_analytic_distribution the line object + it's a new Id, so we cannot assign related fields. + """ + self.ensure_one() + model_obj = self.env["account.analytic.distribution.model"].with_context( + get_distributiion_model_id=True + ) + + args = { + "product_id": self.product_id.id, + "product_categ_id": self.product_id.categ_id.id, + "partner_id": self.partner_id.id, + "partner_category_id": self.partner_id.category_id.ids, + "account_prefix": self.account_id.code, + "company_id": self.company_id.id, + "date": self._get_date(self).strftime("%Y-%m-%d"), + } + + model = model_obj._get_distribution(args) + self.distribution_model_id = model.id if model else False diff --git a/account_analytic_distribution_model_recalculate/pyproject.toml b/account_analytic_distribution_model_recalculate/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/account_analytic_distribution_model_recalculate/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_analytic_distribution_model_recalculate/readme/CONTRIBUTORS.md b/account_analytic_distribution_model_recalculate/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..f0ffd5f8a6 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- APSL - Nagarro \<\> + - Bernat Obrador diff --git a/account_analytic_distribution_model_recalculate/readme/DESCRIPTION.md b/account_analytic_distribution_model_recalculate/readme/DESCRIPTION.md new file mode 100644 index 0000000000..286e677d51 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module allows you to regenerate the analytic distribution of the journal items, that were generated by the distribution model. + +It adds the posibility to add a Start Date and End Date for the distribution models too. \ No newline at end of file diff --git a/account_analytic_distribution_model_recalculate/readme/USAGE.md b/account_analytic_distribution_model_recalculate/readme/USAGE.md new file mode 100644 index 0000000000..69deba4495 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/readme/USAGE.md @@ -0,0 +1,34 @@ +1. **Navigate to Analytic Distribution Models** + +- Go to Invoicing -> Configuration -> Analytic Distribution Models. + +2. **Create or Edit a Distribution Model** + +- Create a new distribution model or edit an existing one. +- Set the **Start Date** and **End Date** to define the active period for the distribution. Only distributions within this date range will be applied. +- Define filters such as **Partner** and **Account Prefix** to control when the model should apply. + +3. **Create an Invoice or Vendor Bill** + +- Select a customer and an account that match the conditions set in the distribution model. +- If the invoice has a date, the system will use it to filter applicable distribution models; otherwise, it will use the current date. + +4. **Use the Recalculate Function** + +- Go to **Analytic Distribution Models**. +- Enable the **Recalculate** option on the model you want to update. +- Modify the analytic distribution as needed. +- Click the **Recalculate** button. (Partner and account prefix needs to be set) +- All journal items originally updated using this model, and still within its date range and matching its criteria, will be recalculated, using the current distribution of the model. + +## **Sync Distribution Models with Journal Items** + +You can use the **Sync** button to associate all journal items that match the distribution model's criteria. + +This is especially useful in the following cases: + +- Journal items were created **before** the distribution model existed. +- The model has been **updated or changed**, and you want to reassign journal items accordingly. +- You need to **sync lines** from other entries that now match the model's conditions. + +By syncing, the system will disassociate any previous links and reassign journal items based on the current configuration of the distribution model. diff --git a/account_analytic_distribution_model_recalculate/static/description/icon.png b/account_analytic_distribution_model_recalculate/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/account_analytic_distribution_model_recalculate/static/description/icon.png differ diff --git a/account_analytic_distribution_model_recalculate/static/description/index.html b/account_analytic_distribution_model_recalculate/static/description/index.html new file mode 100644 index 0000000000..3e468d4f8a --- /dev/null +++ b/account_analytic_distribution_model_recalculate/static/description/index.html @@ -0,0 +1,495 @@ + + + + + +Account Analytic Distribution Model Recalculate + + + +
+

Account Analytic Distribution Model Recalculate

+ + +

Beta License: AGPL-3 OCA/account-analytic Translate me on Weblate Try me on Runboat

+

This module allows you to regenerate the analytic distribution of the +journal items, that were generated by the distribution model.

+

It adds the posibility to add a Start Date and End Date for the +distribution models too.

+

Table of contents

+ +
+

Usage

+
    +
  1. Navigate to Analytic Distribution Models
  2. +
+
    +
  • Go to Invoicing -> Configuration -> Analytic Distribution Models.
  • +
+
    +
  1. Create or Edit a Distribution Model
  2. +
+
    +
  • Create a new distribution model or edit an existing one.
  • +
  • Set the Start Date and End Date to define the active period +for the distribution. Only distributions within this date range will +be applied.
  • +
  • Define filters such as Partner and Account Prefix to control +when the model should apply.
  • +
+
    +
  1. Create an Invoice or Vendor Bill
  2. +
+
    +
  • Select a customer and an account that match the conditions set in the +distribution model.
  • +
  • If the invoice has a date, the system will use it to filter +applicable distribution models; otherwise, it will use the current +date.
  • +
+
    +
  1. Use the Recalculate Function
  2. +
+
    +
  • Go to Analytic Distribution Models.
  • +
  • Enable the Recalculate option on the model you want to update.
  • +
  • Modify the analytic distribution as needed.
  • +
  • Click the Recalculate button. (Partner and account prefix needs +to be set)
  • +
  • All journal items originally updated using this model, and still +within its date range and matching its criteria, will be +recalculated, using the current distribution of the model.
  • +
+
+

Sync Distribution Models with Journal Items

+

You can use the Sync button to associate all journal items that +match the distribution model’s criteria.

+

This is especially useful in the following cases:

+
    +
  • Journal items were created before the distribution model existed.
  • +
  • The model has been updated or changed, and you want to reassign +journal items accordingly.
  • +
  • You need to sync lines from other entries that now match the +model’s conditions.
  • +
+

By syncing, the system will disassociate any previous links and reassign +journal items based on the current configuration of the distribution +model.

+
+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • APSL-Nagarro
  • +
  • Bernat Obrador
  • +
+
+
+

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:

+

BernatObrador

+

This module is part of the OCA/account-analytic project on GitHub.

+

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

+
+
+
+ + diff --git a/account_analytic_distribution_model_recalculate/tests/__init__.py b/account_analytic_distribution_model_recalculate/tests/__init__.py new file mode 100644 index 0000000000..2e4e394b7c --- /dev/null +++ b/account_analytic_distribution_model_recalculate/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_analytic_distribution_model diff --git a/account_analytic_distribution_model_recalculate/tests/test_account_analytic_distribution_model.py b/account_analytic_distribution_model_recalculate/tests/test_account_analytic_distribution_model.py new file mode 100644 index 0000000000..07c4c94361 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/tests/test_account_analytic_distribution_model.py @@ -0,0 +1,464 @@ +# Copyright 2024 (APSL - Nagarro) Bernat Obrador +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import datetime, timedelta + +from freezegun import freeze_time + +from odoo.exceptions import ValidationError +from odoo.fields import Date +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestDistributionModelDate(TransactionCase): + @classmethod + @freeze_time("2024-01-01") + def setUpClass(cls): + super().setUpClass() + + cls.analytic_plan_1 = cls.env["account.analytic.plan"].create( + { + "name": "Plan 1", + } + ) + + cls.product = cls.env.ref("product.product_product_1") + cls.financial_account = cls.product._get_product_accounts()["income"] + + cls.analytic_account_1 = cls.env["account.analytic.account"].create( + {"name": "Account 1", "plan_id": cls.analytic_plan_1.id} + ) + + cls.partner_a = cls.env["res.partner"].create( + {"name": "partner_a", "company_id": False} + ) + cls.partner_b = cls.env["res.partner"].create( + {"name": "partner_b", "company_id": False} + ) + + cls.distribution_1 = cls.env["account.analytic.distribution.model"].create( + { + "partner_id": cls.partner_a.id, + "analytic_distribution": {cls.analytic_account_1.id: 100}, + "start_date": datetime.now().date() - timedelta(days=5), + "end_date": datetime.now().date() + timedelta(days=5), + "recalculate": True, + } + ) + + cls.distribution_2 = cls.env["account.analytic.distribution.model"].create( + { + "partner_id": cls.partner_b.id, + "analytic_distribution": {cls.analytic_account_1.id: 30}, + "start_date": datetime.now().date() + timedelta(days=5), + "end_date": datetime.now().date() + timedelta(days=10), + "recalculate": True, + } + ) + + cls.partner = cls.env["res.partner"].create({"name": "Acme Corp"}) + cls.partner_category = cls.env["res.partner.category"].create({"name": "VIP"}) + cls.product = cls.env["product.product"].create({"name": "Product"}) + cls.product_categ = cls.env["product.category"].create({"name": "Electro"}) + + @freeze_time("2024-01-01") + def test_constraints(self): + distribution = self.env["account.analytic.distribution.model"].create( + { + "partner_id": self.partner_a.id, + } + ) + with self.assertRaises(ValidationError): + distribution.start_date = datetime.now().date() - timedelta(days=5) + distribution.end_date = datetime.now().date() + timedelta(days=5) + distribution._check_duplicate_dates() + + with self.assertRaises(ValidationError): + distribution.start_date = datetime.now().date() - timedelta(days=5) + distribution._check_duplicate_dates() + + with self.assertRaises(ValidationError): + distribution.end_date = datetime.now().date() + timedelta(days=3) + distribution._check_duplicate_dates() + + @freeze_time("2024-01-01") + def test_distribution_model_with_dates_inside_period(self): + invoice = self.env["account.move"].create( + { + "partner_id": self.partner_a.id, + "move_type": "out_invoice", + "invoice_date": datetime.now().date(), + "invoice_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "quantity": 1, + "price_unit": 100, + }, + ) + ], + } + ) + + self.assertEqual(invoice.line_ids[0].account_id, self.financial_account) + self.assertEqual( + invoice.line_ids[0].analytic_distribution, + self.distribution_1.analytic_distribution, + ) + + @freeze_time("2024-01-01") + def test_distribution_model_with_dates_outside_period(self): + invoice = self.env["account.move"].create( + { + "partner_id": self.partner_b.id, + "move_type": "out_invoice", + "invoice_date": datetime.now().date(), + "invoice_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "quantity": 1, + "price_unit": 100, + }, + ) + ], + } + ) + + self.assertFalse( + invoice.line_ids[0].analytic_distribution, + ) + + @freeze_time("2024-01-01") + def test_action_recalculate_analytic_lines_applies_changes(self): + self.distribution_1.analytic_distribution = False + + move = self.env["account.move"].create( + { + "move_type": "entry", + "date": datetime.now().date(), + "line_ids": [ + ( + 0, + 0, + { + "name": "test", + "account_id": self.financial_account.id, + "partner_id": self.partner_a.id, + "debit": 100.0, + "credit": 0.0, + }, + ), + ( + 0, + 0, + { + "name": "counter", + "account_id": self.financial_account.id, + "debit": 0.0, + "credit": 100.0, + }, + ), + ], + } + ) + move.action_post() + line = move.line_ids.filtered(lambda line: line.partner_id == self.partner_a) + self.assertFalse(line.analytic_distribution) + + self.distribution_1.analytic_distribution = { + self.analytic_account_1.id: 100, + } + + with self.assertRaises(ValidationError): + # Error when no prefix is defined + self.distribution_1.action_recalculate_analytic_lines() + + self.distribution_1.account_prefix = self.financial_account.code + + result = self.distribution_1.action_recalculate_analytic_lines() + + self.assertEqual( + line.analytic_distribution, self.distribution_1.analytic_distribution + ) + self.assertEqual(result["tag"], "display_notification") + self.assertIn( + "analytic lines have been recalculated", result["params"]["message"] + ) + + @freeze_time("2024-01-01") + def test_action_recalculate_analytic_lines_no_applies_changes(self): + move = self.env["account.move"].create( + { + "move_type": "entry", + "date": datetime.now().date(), + "line_ids": [ + ( + 0, + 0, + { + "name": "test", + "account_id": self.financial_account.id, + "partner_id": self.partner_a.id, + "debit": 100.0, + "credit": 0.0, + }, + ), + ( + 0, + 0, + { + "name": "counter", + "account_id": self.financial_account.id, + "debit": 0.0, + "credit": 100.0, + }, + ), + ], + } + ) + move.action_post() + line = move.line_ids.filtered(lambda line: line.partner_id == self.partner_a) + self.assertEqual( + line.analytic_distribution, self.distribution_1.analytic_distribution + ) + + self.distribution_1.write( + { + "start_date": datetime.now().date() + timedelta(days=60), + "end_date": datetime.now().date() + timedelta(days=120), + } + ) + self.distribution_1.analytic_distribution = False + self.distribution_1.account_prefix = self.financial_account.code + + result = self.distribution_1.action_recalculate_analytic_lines() + + self.assertTrue(line.analytic_distribution) + # Confirms that the distribution is not applied + # because the date is out of the range + self.assertFalse( + line.analytic_distribution == self.distribution_1.analytic_distribution + ) + self.assertEqual(result["tag"], "display_notification") + self.assertIn( + "No analytic lines have been recalculated", result["params"]["message"] + ) + + @freeze_time("2024-01-01") + def test_no_recalculate_lines_from_other_model(self): + move = self.env["account.move"].create( + { + "move_type": "entry", + "date": datetime.now().date(), + "line_ids": [ + ( + 0, + 0, + { + "name": "test", + "account_id": self.financial_account.id, + "partner_id": self.partner_a.id, + "debit": 100.0, + "credit": 0.0, + }, + ), + ( + 0, + 0, + { + "name": "counter", + "account_id": self.financial_account.id, + "debit": 0.0, + "credit": 100.0, + }, + ), + ], + } + ) + move.action_post() + line = move.line_ids.filtered(lambda line: line.partner_id == self.partner_a) + line.move_id.date = datetime.now().date() + timedelta(days=5) + self.assertEqual( + line.analytic_distribution, self.distribution_1.analytic_distribution + ) + + self.distribution_2.account_prefix = self.financial_account.code + self.distribution_2.partner_id = self.partner_a.id + result = self.distribution_2.action_recalculate_analytic_lines() + + self.assertEqual(line.partner_id, self.distribution_2.partner_id) + self.assertEqual(line.move_id.date, self.distribution_2.start_date) + self.assertEqual(line.account_id.code, self.distribution_2.account_prefix) + + self.assertIn( + "No analytic lines have been recalculated", result["params"]["message"] + ) + self.assertTrue( + line.analytic_distribution != self.distribution_2.analytic_distribution + ) + + @freeze_time("2024-01-01") + def test_display_name_full_info_with_dates(self): + record = self.env["account.analytic.distribution.model"].create( + { + "account_prefix": "123", + "partner_id": self.partner.id, + "partner_category_id": self.partner_category.id, + "product_id": self.product.id, + "product_categ_id": self.product_categ.id, + "start_date": Date.from_string("2024-01-01"), + "end_date": Date.from_string("2024-12-31"), + } + ) + record._compute_display_name() + + self.assertEqual( + record.display_name, + "123 | Acme Corp | VIP | Product | Electro (2024-01-01 - 2024-12-31)", + ) + + @freeze_time("2024-01-01") + def test_action_sync_lines(self): + self.distribution_1.partner_id = False + self.distribution_1.account_prefix = "123" + move = self.env["account.move"].create( + { + "move_type": "entry", + "date": datetime.now().date(), + "line_ids": [ + ( + 0, + 0, + { + "name": "line_to_sync", + "account_id": self.financial_account.id, + "partner_id": self.partner_a.id, + "debit": 100.0, + "credit": 0.0, + }, + ), + ( + 0, + 0, + { + "name": "counter_line", + "account_id": self.financial_account.id, + "debit": 0.0, + "credit": 100.0, + }, + ), + ], + } + ) + move.action_post() + + self.assertFalse(move.line_ids[0].distribution_model_id) + self.assertFalse(move.line_ids[1].distribution_model_id) + + self.distribution_1.partner_id = self.partner_a.id + self.distribution_1.account_prefix = self.financial_account.code + + self.distribution_1.action_sync_lines() + + self.assertEqual( + move.line_ids[0].distribution_model_id.id, self.distribution_1.id + ) + self.assertFalse(move.line_ids[1].distribution_model_id) + + @freeze_time("2024-01-01") + def test_display_name_partial_fields(self): + record = self.env["account.analytic.distribution.model"].create( + {"partner_id": self.partner.id} + ) + record._compute_display_name() + # Only partner, no dates + self.assertIn("Acme Corp", record.display_name) + self.assertNotIn("-", record.display_name) + + @freeze_time("2024-01-01") + def test_get_distribution_no_match(self): + # Should return False when no distribution model matches + vals = { + "product_id": False, + "product_categ_id": False, + "partner_id": False, + "partner_category_id": [], + "account_prefix": "999", + "company_id": self.env.company.id, + "date": "2024-01-01", + } + result = self.env["account.analytic.distribution.model"]._get_distribution(vals) + self.assertFalse(result) + + @freeze_time("2024-01-01") + def test_check_score_for_dates_always_one(self): + model = self.env["account.analytic.distribution.model"].create( + {"start_date": Date.from_string("2024-01-01")} + ) + self.assertEqual(model._check_score("start_date", "2024-01-01"), 1) + self.assertEqual(model._check_score("end_date", "2024-01-01"), 1) + + @freeze_time("2024-01-01") + def test_create_domain_for_date_and_fallback(self): + model = self.env["account.analytic.distribution.model"] + + # Date-specific branch + domain_date = model._create_domain("date", "2024-01-01") + self.assertTrue(any(isinstance(x, tuple) for x in domain_date)) + + # Fallback branch + domain_other = model._create_domain("partner_id", self.partner.id) + self.assertTrue( + any(cond[0] == "partner_id" for cond in domain_other), + f"Expected partner_id in domain, got {domain_other}", + ) + + @freeze_time("2024-01-01") + def test_get_domain_variants(self): + # Only start_date + model = self.env["account.analytic.distribution.model"].create( + {"start_date": Date.from_string("2024-01-01")} + ) + domain = model._get_domain() + self.assertIn(("end_date", ">=", model.start_date), domain) + + # Only end_date + model = self.env["account.analytic.distribution.model"].create( + {"end_date": Date.from_string("2024-12-31")} + ) + domain = model._get_domain() + self.assertIn(("start_date", "<=", model.end_date), domain) + + # Without account_prefix + model = self.env["account.analytic.distribution.model"].create( + {"partner_id": self.partner.id} + ) + domain = model._get_domain() + self.assertIn(("account_prefix", "=", False), domain) + + @freeze_time("2024-01-01") + def test_get_lines_domain_variants_and_constraints(self): + # Case with recalculate = False (should not raise, returns list) + model = self.env["account.analytic.distribution.model"].create( + { + "recalculate": False, + "partner_id": self.partner.id, + "account_prefix": "123", + } + ) + domain = model._get_lines_domain() + self.assertIsInstance(domain, list) + + # Case missing partner_id and account_prefix -> must raise + model = self.env["account.analytic.distribution.model"].create( + {"recalculate": True} + ) + with self.assertRaises(ValidationError): + model._get_lines_domain() diff --git a/account_analytic_distribution_model_recalculate/views/account_analytic_distribution_model.xml b/account_analytic_distribution_model_recalculate/views/account_analytic_distribution_model.xml new file mode 100644 index 0000000000..db6d810ff9 --- /dev/null +++ b/account_analytic_distribution_model_recalculate/views/account_analytic_distribution_model.xml @@ -0,0 +1,78 @@ + + + + + account.analytic.distribution.model.tree.inherit + account.analytic.distribution.model + + + + + + + + +