diff --git a/account_asset_transfer_extension/README.rst b/account_asset_transfer_extension/README.rst new file mode 100644 index 000000000..b06133df5 --- /dev/null +++ b/account_asset_transfer_extension/README.rst @@ -0,0 +1,75 @@ +================================ +Account Asset Transfer Extension +================================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6299fa0e96a82c79095d78f65bb11b03fd9e95517f45414bf2d7c9a8d6ff7b8d + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-NuoBiT%2Fodoo--addons-lightgray.png?logo=github + :target: https://github.com/NuoBiT/odoo-addons/tree/18.0/account_asset_transfer_extension + :alt: NuoBiT/odoo-addons + +|badge1| |badge2| |badge3| + +This module extends the OCA ``account_asset_transfer`` module adding: + +- A "Transferred" state on assets to track which assets have been + transferred via the AUC (Assets Under Construction) transfer wizard. +- Fields ``transfer_move_id`` and ``date_transfer`` to link transferred + assets to their transfer journal entry. +- Computed fields ``from_asset_ids`` and ``to_asset_ids`` to navigate + between source and destination assets. +- A "Revert Transfer" wizard to undo AUC transfers, restoring assets to + their original state. +- Protection against accidental deletion of transfer journal entries + (CURS moves) when unposting depreciation lines. + +**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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* NuoBiT Solutions SL + +Contributors +------------ + +- `NuoBiT `__: + + - Kilian Niubo kniubo@nuobit.com + - Eric Antones eantones@nuobit.com + - Deniz Gallo dgallo@nuobit.com + +Maintainers +----------- + +This module is part of the `NuoBiT/odoo-addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/account_asset_transfer_extension/__init__.py b/account_asset_transfer_extension/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/account_asset_transfer_extension/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/account_asset_transfer_extension/__manifest__.py b/account_asset_transfer_extension/__manifest__.py new file mode 100644 index 000000000..452c6a25c --- /dev/null +++ b/account_asset_transfer_extension/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright NuoBiT Solutions SL - Kilian Niubo +# Copyright NuoBiT Solutions SL - Eric Antones +# Copyright 2025 NuoBiT Solutions SL - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +{ + "name": "Account Asset Transfer Extension", + "summary": "This module extends account_asset_transfer ", + "author": "NuoBiT Solutions SL", + "category": "Accounting", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "website": "https://github.com/NuoBiT/odoo-addons", + "depends": ["account_asset_transfer"], + "data": [ + "security/ir.model.access.csv", + "views/account_asset_views.xml", + "wizards/account_asset_transfer_revert.xml", + ], +} diff --git a/account_asset_transfer_extension/i18n/ca.po b/account_asset_transfer_extension/i18n/ca.po new file mode 100644 index 000000000..cb99378e4 --- /dev/null +++ b/account_asset_transfer_extension/i18n/ca.po @@ -0,0 +1,185 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_asset_transfer_extension +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-12-23 16:15+0000\n" +"PO-Revision-Date: 2022-12-23 16:15+0000\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_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> Journal entries to remove: %s" +msgstr "> Assentaments comptables a eliminar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> New assets to remove: %s" +msgstr "> Actius nous a eliminar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> Transferred assets to restore: %s" +msgstr "> Actius transferits a restaurar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Active Model not defined" +msgstr "El model actiu no ha estat definit" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__date_transfer +msgid "Asset Transfer Date" +msgstr "Data de la transferència de l'actiu" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__from_asset_ids +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "From Assets" +msgstr "Actius origen" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "More than one move with the same to_asset found" +msgstr "S'ha trobat més d'un moviment amb el mateix actiu de destinació" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "No assets selected" +msgstr "No hi ha actius seleccionats" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Nothing to revert" +msgstr "Res a revertir" + +#. module: account_asset_transfer_extension +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_transfer_revert_view_form +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "Revert Transfer" +msgstr "Revertir transferència" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "Revert Transfer AUC to Asset" +msgstr "Revertir transferència AUC de l'actiu" + +#. module: account_asset_transfer_extension +#: model:ir.actions.server,name:account_asset_transfer_extension.action_asset_transfer_revert_from_list +msgid "Revert Transfer Asset" +msgstr "Revertir transferència d'actiu" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_asset_transfer_revert +msgid "Revert Transferred Asset" +msgstr "Revertir actius transferits" + +#. module: account_asset_transfer_extension +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_transfer_revert_view_form +msgid "Tansfer Assets?" +msgstr "Transferir actius?" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The journal entry %s has lines without asset" +msgstr "L'assentament comptable %s té línies sense actius" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The journal entry assets has inconsistencies with de from/to assets" +msgstr "" +"Els actius de l'assentament comptable tenen inconsistències amb els actius " +"d'origen i destinació" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The next actions will be taken: " +msgstr "Es realitzaran les accions següents: " + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__to_asset_ids +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "To Assets" +msgstr "Actius nous" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__transfer_move_id +msgid "Transfer Move id" +msgstr "Moviment de transferència" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields.selection,name:account_asset_transfer_extension.selection__account_asset__state__transferred +msgid "Transferred" +msgstr "Transferit" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Unexpected number of init entries found on deprecation line" +msgstr "Nombre inesperat d'entrades inicials trobades a la línia d'amortització" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__warning_message +msgid "Warning Message" +msgstr "Missatge d'avís" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "" +"When asset has from_asset_ids, state must be open, close or removed. Please," +" review asset: %s" +msgstr "" +"Quan l'actiu té actius d'origen, l'estat ha de ser en execució, tancat o " +"eliminat. Si us plau, reviseu l'actiu: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "" +"When asset has to_asset_ids, state must be transferred. Please, review " +"asset: %s" +msgstr "" +"Quan l'actiu té actius nous, l'estat ha de ser transferit. Si us plau, " +"reviseu l'actiu: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset_line.py:0 +#, python-format +msgid "" +"You cannot unpost this entry because it is a transfer move (%s) linked to " +"transferred assets. Use the 'Revert Transfer' action instead." +msgstr "" +"No es pot desassentar aquest apunt perquè és un moviment de transferència " +"(%s) vinculat a actius transferits. Utilitzeu l'acció 'Revertir " +"transferència'." + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_move.py:0 +#, python-format +msgid "" +"You can't modify or delete a journal item on journal entries with " +"transferred assets" +msgstr "" +"No es pot modificar o eliminar un apunt comptable en assentaments amb " +"actius transferits." diff --git a/account_asset_transfer_extension/i18n/es.po b/account_asset_transfer_extension/i18n/es.po new file mode 100644 index 000000000..8e8c41808 --- /dev/null +++ b/account_asset_transfer_extension/i18n/es.po @@ -0,0 +1,269 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_asset_transfer_extension +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-12-23 16:15+0000\n" +"PO-Revision-Date: 2022-12-23 16:15+0000\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_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> Journal entries to remove: %s" +msgstr "> Apuntes contables a eliminar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> New assets to remove: %s" +msgstr "> Nuevos activos a eliminar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "> Transferred assets to restore: %s" +msgstr "> Activos transferidos a restaurar: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Active Model not defined" +msgstr "El modelo activo no ha sido definido" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_asset +msgid "Asset" +msgstr "Activo" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__date_transfer +msgid "Asset Transfer Date" +msgstr "Fecha de la transferencia del activo" + +#. module: account_asset_transfer_extension +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_transfer_revert_view_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__display_name +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer__display_name +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__display_name +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move__display_name +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move_line__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__from_asset_ids +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "From Assets" +msgstr "Activos origen" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__id +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer__id +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__id +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move__id +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move_line__id +msgid "ID" +msgstr "ID" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_move +msgid "Journal Entry" +msgstr "Asiento contable" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_move_line +msgid "Journal Item" +msgstr "Apunte contable" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset____last_update +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer____last_update +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert____last_update +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move____last_update +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_move_line____last_update +msgid "Last Modified on" +msgstr "Última modificación" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "More than one move with the same to_asset found" +msgstr "Mas de un movimiento con el mismo activo de destino encontrado" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "No assets selected" +msgstr "No hay activos seleccionados" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Nothing to revert" +msgstr "Nada a revertir" + +#. module: account_asset_transfer_extension +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_transfer_revert_view_form +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "Revert Transfer" +msgstr "Revertir transferencia" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "Revert Transfer AUC to Asset" +msgstr "Revertir transferencia AUC del activo" + +#. module: account_asset_transfer_extension +#: model:ir.actions.server,name:account_asset_transfer_extension.action_asset_transfer_revert_from_list +msgid "Revert Transfer Asset" +msgstr "Revertir transferencia de activo" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_asset_transfer_revert +msgid "Revert Transferred Asset" +msgstr "Revertir activos transferidos" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__state +msgid "Status" +msgstr "Estado" + +#. module: account_asset_transfer_extension +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_transfer_revert_view_form +msgid "Tansfer Assets?" +msgstr "Transferir activos?" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The journal entry %s has lines without asset" +msgstr "El asiento contable %s tiene líneas sin activos" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The journal entry assets has inconsistencies with de from/to assets" +msgstr "Los activos del asiento contable tienen inconsistencias con el origen y destino de los activos" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "The next actions will be taken: " +msgstr "Se realizaran las siguientes acciones: " + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__to_asset_ids +#: model_terms:ir.ui.view,arch_db:account_asset_transfer_extension.account_asset_view_form +msgid "To Assets" +msgstr "Activos nuevos" + +#. module: account_asset_transfer_extension +#: model:ir.model,name:account_asset_transfer_extension.model_account_asset_transfer +msgid "Transfer Asset" +msgstr "Transferir Activo" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset__transfer_move_id +msgid "Transfer Move id" +msgstr "Movimiento de transferencia" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields.selection,name:account_asset_transfer_extension.selection__account_asset__state__transferred +msgid "Transferred" +msgstr "Transferido" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/wizard/account_asset_transfer_revert.py:0 +#, python-format +msgid "Unexpected number of init entries found on deprecation line" +msgstr "Número inesperado de entradas init encontradas en la línea de desaprobación" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,field_description:account_asset_transfer_extension.field_account_asset_transfer_revert__warning_message +msgid "Warning Message" +msgstr "Mensaje de advertencia" + +#. module: account_asset_transfer_extension +#: model:ir.model.fields,help:account_asset_transfer_extension.field_account_asset__state +msgid "" +"When an asset is created, the status is 'Draft'.\n" +"If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted to the accounting.\n" +"If the last depreciation line is posted, the asset goes into the 'Close' status.\n" +"When the removal entries are generated, the asset goes into the 'Removed' status." +msgstr "" +"Cuando se crea un activo, el estado es 'Borrador'.\n" +"Si el activo es confirmado, el estado pasa a 'En ejecución' y las líneas de amortización pueden ser creadas en la contabilizada.\n" +"Si se crea la última línea de amortización, el activo pasa a estado 'Cerrado'.\n" +"Cuando se generan los asientos de eliminación, el activo pasa a estado 'Eliminado'." + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "" +"When asset has from_asset_ids, state must be open, close or removed. Please," +" review asset: %s" +msgstr "Cuando los activos tienen activos de origen el estado debe ser en ejecucion, cerrar o eliminado." +"Por favor, revise el activo: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_asset.py:0 +#, python-format +msgid "" +"When asset has to_asset_ids, state must be transferred. Please, review " +"asset: %s" +msgstr "Cuando un activo tiene activos nuevos, el estado debe ser transferido." +"Por favor, revise el activo: %s" + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_move.py:0 +#, python-format +msgid "" +"You cannot unpost this entry because it is a transfer move (%s) linked to " +"transferred assets. Use the 'Revert Transfer' action instead." +msgstr "" +"No se puede desasentar este apunte porque es un movimiento de transferencia " +"(%s) vinculado a activos transferidos. Use la acción 'Revertir " +"transferencia' en su lugar." + +#. module: account_asset_transfer_extension +#: code:addons/account_asset_transfer_extension/models/account_move.py:0 +#, python-format +msgid "" +"You can't modify or delete a journal item on journal entries with " +"transferred assets" +msgstr "No se puede modificar o eliminar un asiento en los asientos con activos transferidos." diff --git a/account_asset_transfer_extension/models/__init__.py b/account_asset_transfer_extension/models/__init__.py new file mode 100644 index 000000000..a087b4f62 --- /dev/null +++ b/account_asset_transfer_extension/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_asset +from . import account_asset_line +from . import account_move diff --git a/account_asset_transfer_extension/models/account_asset.py b/account_asset_transfer_extension/models/account_asset.py new file mode 100644 index 000000000..16ada2a85 --- /dev/null +++ b/account_asset_transfer_extension/models/account_asset.py @@ -0,0 +1,103 @@ +# Copyright NuoBiT Solutions SL - Kilian Niubo +# Copyright NuoBiT Solutions SL - Eric Antones +# Copyright 2025 NuoBiT Solutions SL - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountAsset(models.Model): + _inherit = "account.asset" + + from_asset_ids = fields.Many2many( + string="From Assets", + comodel_name="account.asset", + compute="_compute_from_asset_ids", + ) + + def _compute_from_asset_ids(self): + for rec in self: + move_lines = rec.account_move_line_ids.filtered( + lambda x, rec=rec: x.move_id != rec.transfer_move_id + ) + move = move_lines.move_id.filtered( + lambda x: x in x.line_ids.asset_id.transfer_move_id + ) + if len(move) > 1: + raise ValidationError( + _("More than one move with the same to_asset found") + ) + rec.from_asset_ids = move.line_ids.asset_id.filtered( + lambda x, move=move: x.transfer_move_id == move + ) + + to_asset_ids = fields.Many2many( + string="To Assets", + comodel_name="account.asset", + compute="_compute_to_asset_ids", + ) + + def _compute_to_asset_ids(self): + for rec in self: + if rec.transfer_move_id: + rec.to_asset_ids = rec.transfer_move_id.line_ids.asset_id.filtered( + lambda x, rec=rec: not x.transfer_move_id + or x.transfer_move_id != rec.transfer_move_id + ) + else: + rec.to_asset_ids = False + + state = fields.Selection( + selection_add=[("transferred", "Transferred")], + ondelete={"transferred": "cascade"}, + ) + date_transfer = fields.Date( + string="Asset Transfer Date", + readonly=True, + ) + transfer_move_id = fields.Many2one( + comodel_name="account.move", + string="Transfer Move id", + readonly=True, + ) + + def revert_transfer(self): + wizard = self.env["account.asset.transfer.revert"].create({}) + wizard._generate_warning_message() + ctx = dict(self.env.context, active_ids=self.ids) + res = { + "name": _("Revert Transfer AUC to Asset"), + "view_mode": "form", + "res_model": "account.asset.transfer.revert", + "target": "new", + "res_id": wizard.id, + "type": "ir.actions.act_window", + "context": ctx, + } + return res + + @api.constrains("state") + def _check_state_to_asset_ids(self): + for rec in self: + if rec.to_asset_ids and rec.state != "transferred": + raise ValidationError( + _( + "When asset has to_asset_ids, state must be transferred. " + "Please, review asset: %s" + ) + % rec.name + ) + + @api.constrains("state") + def _check_state_from_asset_ids(self): + for rec in self: + if rec.from_asset_ids and rec.state not in ["open", "close", "removed"]: + raise ValidationError( + _( + "When asset has from_asset_ids, " + "state must be open, close or removed. " + "Please, review asset: %s" + ) + % rec.name + ) diff --git a/account_asset_transfer_extension/models/account_asset_line.py b/account_asset_transfer_extension/models/account_asset_line.py new file mode 100644 index 000000000..7653fd651 --- /dev/null +++ b/account_asset_transfer_extension/models/account_asset_line.py @@ -0,0 +1,26 @@ +# Copyright 2026 NuoBiT Solutions SL - Eric Antones +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, models +from odoo.exceptions import UserError + + +class AccountAssetLine(models.Model): + _inherit = "account.asset.line" + + def unlink_move(self): + for line in self: + if line.move_id: + transferred_assets = self.env["account.asset"].search( + [("transfer_move_id", "=", line.move_id.id)], limit=1 + ) + if transferred_assets: + raise UserError( + _( + "You cannot unpost this entry because it is a " + "transfer move (%s) linked to transferred assets." + " Use the 'Revert Transfer' action instead." + ) + % line.move_id.display_name + ) + return super().unlink_move() diff --git a/account_asset_transfer_extension/models/account_move.py b/account_asset_transfer_extension/models/account_move.py new file mode 100644 index 000000000..587aceed4 --- /dev/null +++ b/account_asset_transfer_extension/models/account_move.py @@ -0,0 +1,42 @@ +# Copyright NuoBiT Solutions SL - Kilian Niubo +# Copyright NuoBiT Solutions SL - Eric Antones +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class AccountMove(models.Model): + _inherit = "account.move" + + def _check_exists_asset_transfers(self): + if not self.env.context.get("force_delete", False): + for rec in self: + if rec.line_ids.asset_id.mapped("transfer_move_id"): + raise ValidationError( + _( + "You can't modify or delete a journal item " + "on journal entries with transferred assets" + ) + ) + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + def write(self, vals): + self.move_id.filtered( + lambda x: x.state != "posted" + )._check_exists_asset_transfers() + return super().write(vals) + + @api.model_create_multi + def create(self, vals_list): + self.env["account.move"].browse( + [x["move_id"] for x in vals_list] + )._check_exists_asset_transfers() + return super().create(vals_list) + + def unlink(self): + self.move_id._check_exists_asset_transfers() + return super().unlink() diff --git a/account_asset_transfer_extension/pyproject.toml b/account_asset_transfer_extension/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/account_asset_transfer_extension/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_asset_transfer_extension/readme/CONTRIBUTORS.md b/account_asset_transfer_extension/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..0355cecbc --- /dev/null +++ b/account_asset_transfer_extension/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [NuoBiT](https://www.nuobit.com): + - Kilian Niubo + - Eric Antones + - Deniz Gallo diff --git a/account_asset_transfer_extension/readme/DESCRIPTION.md b/account_asset_transfer_extension/readme/DESCRIPTION.md new file mode 100644 index 000000000..402537923 --- /dev/null +++ b/account_asset_transfer_extension/readme/DESCRIPTION.md @@ -0,0 +1,12 @@ +This module extends the OCA `account_asset_transfer` module adding: + +- A "Transferred" state on assets to track which assets have been + transferred via the AUC (Assets Under Construction) transfer wizard. +- Fields `transfer_move_id` and `date_transfer` to link transferred + assets to their transfer journal entry. +- Computed fields `from_asset_ids` and `to_asset_ids` to navigate + between source and destination assets. +- A "Revert Transfer" wizard to undo AUC transfers, restoring assets to + their original state. +- Protection against accidental deletion of transfer journal entries + (CURS moves) when unposting depreciation lines. diff --git a/account_asset_transfer_extension/security/ir.model.access.csv b/account_asset_transfer_extension/security/ir.model.access.csv new file mode 100644 index 000000000..6b9a5d987 --- /dev/null +++ b/account_asset_transfer_extension/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_asset_transfer_revert_user,account.asset.transfer.revert,model_account_asset_transfer_revert,account.group_account_user,1,1,1,1 diff --git a/account_asset_transfer_extension/static/description/icon.png b/account_asset_transfer_extension/static/description/icon.png new file mode 100644 index 000000000..1cd641e79 Binary files /dev/null and b/account_asset_transfer_extension/static/description/icon.png differ diff --git a/account_asset_transfer_extension/static/description/index.html b/account_asset_transfer_extension/static/description/index.html new file mode 100644 index 000000000..bc6310ac8 --- /dev/null +++ b/account_asset_transfer_extension/static/description/index.html @@ -0,0 +1,433 @@ + + + + + +Account Asset Transfer Extension + + + +
+

Account Asset Transfer Extension

+ + +

Beta License: AGPL-3 NuoBiT/odoo-addons

+

This module extends the OCA account_asset_transfer module adding:

+
    +
  • A “Transferred” state on assets to track which assets have been +transferred via the AUC (Assets Under Construction) transfer wizard.
  • +
  • Fields transfer_move_id and date_transfer to link transferred +assets to their transfer journal entry.
  • +
  • Computed fields from_asset_ids and to_asset_ids to navigate +between source and destination assets.
  • +
  • A “Revert Transfer” wizard to undo AUC transfers, restoring assets to +their original state.
  • +
  • Protection against accidental deletion of transfer journal entries +(CURS moves) when unposting depreciation lines.
  • +
+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • NuoBiT Solutions SL
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the NuoBiT/odoo-addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/account_asset_transfer_extension/views/account_asset_views.xml b/account_asset_transfer_extension/views/account_asset_views.xml new file mode 100644 index 000000000..8be1d5fc5 --- /dev/null +++ b/account_asset_transfer_extension/views/account_asset_views.xml @@ -0,0 +1,59 @@ + + + account.asset.form.transfer.ext + account.asset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + draft,open,close + + + + diff --git a/account_asset_transfer_extension/wizards/__init__.py b/account_asset_transfer_extension/wizards/__init__.py new file mode 100644 index 000000000..aa9b2d5f5 --- /dev/null +++ b/account_asset_transfer_extension/wizards/__init__.py @@ -0,0 +1,2 @@ +from . import account_asset_transfer +from . import account_asset_transfer_revert diff --git a/account_asset_transfer_extension/wizards/account_asset_transfer.py b/account_asset_transfer_extension/wizards/account_asset_transfer.py new file mode 100644 index 000000000..41c4e01a8 --- /dev/null +++ b/account_asset_transfer_extension/wizards/account_asset_transfer.py @@ -0,0 +1,40 @@ +# Copyright NuoBiT Solutions SL - Kilian Niubo +# Copyright NuoBiT Solutions SL - Eric Antones +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class AccountAssetTransfer(models.TransientModel): + _inherit = "account.asset.transfer" + + def transfer(self): + res = super().transfer() + move = self.env["account.move"].browse(res["domain"][0][2]) + for line in move.line_ids: + if line.asset_id in self.from_asset_ids: + line.asset_id.write( + { + "transfer_move_id": move.id, + "state": "transferred", + "date_remove": False, + "date_transfer": self.date_transfer, + } + ) + return res + + def _get_move_line_from_asset(self, asset): + res = super()._get_move_line_from_asset(asset) + if asset.account_move_line_ids: + asset.account_move_line_ids.ensure_one() + move_line = asset.account_move_line_ids[0] + res.update( + { + "debit": -asset.purchase_value if move_line.balance < 0 else 0.0, + "credit": asset.purchase_value if move_line.balance >= 0 else 0.0, + } + ) + else: + if asset.purchase_value and asset.purchase_value < 0: + res.update({"debit": -asset.purchase_value, "credit": 0.0}) + return res diff --git a/account_asset_transfer_extension/wizards/account_asset_transfer_revert.py b/account_asset_transfer_extension/wizards/account_asset_transfer_revert.py new file mode 100644 index 000000000..fd5870346 --- /dev/null +++ b/account_asset_transfer_extension/wizards/account_asset_transfer_revert.py @@ -0,0 +1,96 @@ +# Copyright NuoBiT Solutions SL - Kilian Niubo +# Copyright NuoBiT Solutions SL - Eric Antones +# Copyright 2025 NuoBiT Solutions SL - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import _, fields, models +from odoo.exceptions import UserError, ValidationError + + +class AccountAssetTransfer(models.TransientModel): + _name = "account.asset.transfer.revert" + _description = "Revert Transferred Asset" + + warning_message = fields.Text(readonly=True) + + def _get_to_asset_ids(self): + active_model = self.env.context.get("active_model") + if not active_model: + raise ValidationError(_("Active Model not defined")) + from_asset_ids = self.env.context.get("active_ids", []) + if not from_asset_ids: + raise UserError(_("No assets selected")) + from_assets = self.env[active_model].browse(from_asset_ids) + return from_assets.mapped("to_asset_ids") + + def _generate_warning_message(self): + self.ensure_one() + to_asset_moves = self._group_assets_by_move(self._get_to_asset_ids()) + if not to_asset_moves: + self.warning_message = _("Nothing to revert") + else: + message_l = [_("The next actions will be taken: ")] + moves = self.env["account.move"].browse( + map(lambda x: x.id, to_asset_moves.keys()) + ) + message_l.append( + _("> Journal entries to remove: %s") % ", ".join(moves.mapped("name")) + ) + to_assets = self.env["account.asset"] + for assets in to_asset_moves.values(): + to_assets |= assets[1] + if to_assets: + message_l.append( + _("> New assets to remove: %s") + % ", ".join(to_assets.mapped("name")) + ) + from_assets = self.env["account.asset"] + for assets in to_asset_moves.values(): + from_assets |= assets[0] + if from_assets: + message_l.append( + _("> Transferred assets to restore: %s") + % ", ".join(from_assets.mapped("name")) + ) + if message_l: + self.warning_message = "\n\n".join(message_l) + + def _group_assets_by_move(self, to_assets): + to_asset_moves = {} + for asset in to_assets: + dps = asset.depreciation_line_ids.filtered(lambda x: x.init_entry) + if len(dps) != 1: + raise ValidationError( + _("Unexpected number of init entries found on deprecation line") + ) + move = dps[0].move_id + if move: + if move in to_asset_moves: + to_asset_moves[move][1] |= asset + else: + to_asset_moves[move] = [asset.from_asset_ids, asset] + return to_asset_moves + + def revert_transfer(self): + to_assets = self._get_to_asset_ids() + if not to_assets: + raise ValidationError(_("Nothing to revert")) + to_asset_moves = self._group_assets_by_move(to_assets) + for move, (from_assets, to_assets) in to_asset_moves.items(): + lines_wo_assets = move.line_ids.filtered(lambda x: not x.asset_id) + if lines_wo_assets: + raise ValidationError( + _("The journal entry %s has lines without asset") % move.name + ) + if set(move.line_ids.asset_id.ids) != set((from_assets | to_assets).ids): + raise ValidationError( + _( + "The journal entry assets has " + "inconsistencies with de from/to assets" + ) + ) + move.button_draft() + move.with_context(force_delete=True).unlink() + to_assets.set_to_draft() + to_assets.unlink() + from_assets.state = "open" diff --git a/account_asset_transfer_extension/wizards/account_asset_transfer_revert.xml b/account_asset_transfer_extension/wizards/account_asset_transfer_revert.xml new file mode 100644 index 000000000..0e13ea2d7 --- /dev/null +++ b/account_asset_transfer_extension/wizards/account_asset_transfer_revert.xml @@ -0,0 +1,38 @@ + + + account.asset.transfer.revert.form + account.asset.transfer.revert + +
+ + + +
+
+
+
+
+ + + Revert Transfer Asset + + + + list + code + + if records: + action = records.revert_transfer() + + +