From 0d714679abad663be52da868744f5b9ffce9a1f8 Mon Sep 17 00:00:00 2001 From: FrankC013 Date: Mon, 8 May 2023 15:52:39 +0200 Subject: [PATCH 1/8] [ADD] account_move_accrual_entry: New module to generate an accrual journal entry Adds smart-button in invoice to access it Create accrual_account_id and accrual_asset_account_type in invoice settings --- account_move_accrual_entry/README.rst | 80 ++++ account_move_accrual_entry/__init__.py | 3 + account_move_accrual_entry/__manifest__.py | 18 + account_move_accrual_entry/i18n/es.po | 102 +++++ account_move_accrual_entry/models/__init__.py | 3 + .../models/account_move.py | 278 +++++++++++ .../models/res_company.py | 15 + .../models/res_config_settings.py | 28 ++ .../readme/CONFIGURE.rst | 4 + .../readme/CONTRIBUTORS.rst | 4 + .../readme/DESCRIPTION.rst | 1 + .../static/description/icon.png | Bin 0 -> 6342 bytes .../static/description/index.html | 430 ++++++++++++++++++ account_move_accrual_entry/tests/__init__.py | 5 + account_move_accrual_entry/tests/common.py | 83 ++++ .../tests/test_account.py | 296 ++++++++++++ .../views/account_move_views.xml | 80 ++++ .../views/res_config_settings_views.xml | 48 ++ 18 files changed, 1478 insertions(+) create mode 100644 account_move_accrual_entry/README.rst create mode 100644 account_move_accrual_entry/__init__.py create mode 100644 account_move_accrual_entry/__manifest__.py create mode 100644 account_move_accrual_entry/i18n/es.po create mode 100644 account_move_accrual_entry/models/__init__.py create mode 100644 account_move_accrual_entry/models/account_move.py create mode 100644 account_move_accrual_entry/models/res_company.py create mode 100644 account_move_accrual_entry/models/res_config_settings.py create mode 100644 account_move_accrual_entry/readme/CONFIGURE.rst create mode 100644 account_move_accrual_entry/readme/CONTRIBUTORS.rst create mode 100644 account_move_accrual_entry/readme/DESCRIPTION.rst create mode 100644 account_move_accrual_entry/static/description/icon.png create mode 100644 account_move_accrual_entry/static/description/index.html create mode 100644 account_move_accrual_entry/tests/__init__.py create mode 100644 account_move_accrual_entry/tests/common.py create mode 100644 account_move_accrual_entry/tests/test_account.py create mode 100644 account_move_accrual_entry/views/account_move_views.xml create mode 100644 account_move_accrual_entry/views/res_config_settings_views.xml diff --git a/account_move_accrual_entry/README.rst b/account_move_accrual_entry/README.rst new file mode 100644 index 000000000..ea05f7a80 --- /dev/null +++ b/account_move_accrual_entry/README.rst @@ -0,0 +1,80 @@ +===================== +Accrual Journal Entry +===================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-nuobit%2Fodoo--addons-lightgray.png?logo=github + :target: https://github.com/nuobit/odoo-addons/tree/14.0/account_move_accrual_entry + :alt: nuobit/odoo-addons + +|badge1| |badge2| |badge3| + +This module creates a journal entry at accrual date and adds a smart-button in the invoice to access it + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to go to invoice settings and set the following parameters: + +* Default accrual account +* Default accrual asset account type + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* NuoBiT Solutions +* S.L. + +Contributors +~~~~~~~~~~~~ + +* `NuoBiT `_: + + * Frank Cespedes + * Eric Antones + +Maintainers +~~~~~~~~~~~ + +.. |maintainer-FrankC013| image:: https://github.com/FrankC013.png?size=40px + :target: https://github.com/FrankC013 + :alt: FrankC013 +.. |maintainer-eantones| image:: https://github.com/eantones.png?size=40px + :target: https://github.com/eantones + :alt: eantones + +Current maintainers: + +|maintainer-FrankC013| |maintainer-eantones| + +This module is part of the `nuobit/odoo-addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/account_move_accrual_entry/__init__.py b/account_move_accrual_entry/__init__.py new file mode 100644 index 000000000..21101d349 --- /dev/null +++ b/account_move_accrual_entry/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import models diff --git a/account_move_accrual_entry/__manifest__.py b/account_move_accrual_entry/__manifest__.py new file mode 100644 index 000000000..232e44fd4 --- /dev/null +++ b/account_move_accrual_entry/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright NuoBiT Solutions, S.L. () +# Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +{ + "name": "Accrual Journal Entry", + "summary": "This module create journal entry with accrual date", + "version": "14.0.1.0.0", + "category": "Accounting", + "author": "NuoBiT Solutions, S.L.", + "website": "https://github.com/nuobit/odoo-addons", + "license": "AGPL-3", + "depends": ["account"], + "data": [ + "views/account_move_views.xml", + "views/res_config_settings_views.xml", + ], + "maintainers": ["FrankC013", "eantones"], +} diff --git a/account_move_accrual_entry/i18n/es.po b/account_move_accrual_entry/i18n/es.po new file mode 100644 index 000000000..b2c568eb9 --- /dev/null +++ b/account_move_accrual_entry/i18n/es.po @@ -0,0 +1,102 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_move_accrual_entry +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-04-27 10:58+0000\n" +"PO-Revision-Date: 2023-04-27 10:58+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_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii +msgid "" +"Accrual Parameters\n" +" " +msgstr "" +"Parametros de periodificación\n" +" " + +#. module: account_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.view_move_form +msgid "Accrual entry" +msgstr "Asiento Periodif." + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__account_id +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii +msgid "Account" +msgstr "Cuenta" + +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "The accrual date cannot be greater than the date of the journal entry" +msgstr "La fecha de periodificación no puede ser posterior a la fecha de la factura" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__accrual_account_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__accrual_account_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__accrual_account_id +msgid "Accrual Account" +msgstr "Cuenta de periodificación" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_bank_statement_line__accrual_date +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__accrual_date +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__accrual_date +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_payment__accrual_date +msgid "Accrual Date" +msgstr "Fecha de periodificación" + +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "You cannot create %s with this account %s" +msgstr "No puedes crear %s con esta cuenta %s" + +#. module: account_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii +msgid "Accrual parameters used on sale invoices" +msgstr "Parametros de periodificación usados en facturas de venta" + +#. module: account_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii +msgid "Asset account type" +msgstr "Tipo de cuenta de activo" + +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "Journal entry with accrual date for assets not allowed." +msgstr "Asiento contable con fecha de periodificación para activos no permitido." + +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "Please set the accrual account in the invoincing settings." +msgstr "Por favor, establezca la cuenta de periodificación en la configuración de facturación." + +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "Please set the account type for assets in the invoincing settings." +msgstr "Por favor, establezca el tipo de cuenta para activos en la configuración de facturación." + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__accrual_asset_account_type_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__accrual_asset_account_type_id +msgid "Account Type for Assets" +msgstr "Tipo de cuenta para activos" + +#. module: account_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.view_move_form +msgid "You have assets added to the invoice" +msgstr "Tienes activos añadidos en la factura" diff --git a/account_move_accrual_entry/models/__init__.py b/account_move_accrual_entry/models/__init__.py new file mode 100644 index 000000000..d710c036a --- /dev/null +++ b/account_move_accrual_entry/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_move +from . import res_config_settings +from . import res_company diff --git a/account_move_accrual_entry/models/account_move.py b/account_move_accrual_entry/models/account_move.py new file mode 100644 index 000000000..83c89cb90 --- /dev/null +++ b/account_move_accrual_entry/models/account_move.py @@ -0,0 +1,278 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class AccountMove(models.Model): + _inherit = "account.move" + + accrual_date = fields.Date(string="Accrual Date") + accrual_move_id = fields.Many2one( + comodel_name="account.move", + relation="accrual_account_move_rel", + column1="move_id", + column2="accrual_move_id", + copy=False, + readonly=True, + ) + + def _get_accrual_account_id(self): + if self.accrual_date: + if not self.env.company.accrual_account_id: + raise UserError( + _("Please set the accrual account in the invoincing settings.") + ) + return self.env.company.accrual_account_id + + def _get_accrual_asset_account_type_id(self): + if not self.env.company.accrual_asset_account_type_id: + raise UserError( + _("Please set the account type for assets in the invoincing settings.") + ) + return self.env.company.accrual_asset_account_type_id + + def _not_asset(self, x): + asset = self.env.company.accrual_asset_account_type_id + return x.accrual_account_id.user_type_id != asset + + def _asset(self, x): + asset = self.env.company.accrual_asset_account_type_id + return x.accrual_account_id.user_type_id == asset + + def _accrual_reconcile(self, rec): + invoice_line_ids = self.invoice_line_ids.filtered( + lambda x: x.accrual_account_id.user_type_id + != self._get_accrual_asset_account_type_id() + ) + for l0, l1 in zip(invoice_line_ids, rec.line_ids): + (l0 | l1).reconcile() + + def _prepare_lines(self): + line_ids = [] + non_asset_invoice_lines = self.invoice_line_ids.filtered( + lambda x: x.accrual_account_id.user_type_id + != self._get_accrual_asset_account_type_id() + ) + for idx in range(2): + for line in non_asset_invoice_lines: + ji = { + "name": line.name, + "date": self.accrual_date, + "account_id": line.account_id.id + if idx == 0 + else line.accrual_account_id.id, + "debit": line.price_subtotal if idx == 0 else 0, + "credit": 0 if idx == 0 else line.price_subtotal, + } + line_ids.append(ji) + return line_ids + + def _create_accrual_move(self): + line_ids = [(0, 0, line_dict) for line_dict in self._prepare_lines()] + return self.env[self._name].create( + { + "partner_id": self.partner_id.id, + "journal_id": self.journal_id.id, + "accrual_date": self.accrual_date, + "date": self.accrual_date, + "move_type": "entry", + "line_ids": line_ids, + } + ) + + def _post(self, soft=True): + res = super(AccountMove, self)._post(soft=soft) + for rec in self: + if rec.accrual_date: + non_asset_lines = rec.invoice_line_ids.filtered(rec._not_asset) + if rec.invoice_line_ids and not non_asset_lines: + raise UserError( + _("Journal entry with accrual date for assets not allowed.") + ) + accrual_move = rec._create_accrual_move() + super(AccountMove, accrual_move)._post(soft=False) + rec.accrual_move_id = accrual_move + rec._accrual_reconcile(accrual_move) + return res + + def button_draft(self): + super().button_draft() + super(AccountMove, self.accrual_move_id).button_draft() + self.accrual_move_id.with_context(force_delete=True).unlink() + + def action_journal_entry(self): + self.ensure_one() + return { + "name": "Accruals assets", + "type": "ir.actions.act_window", + "view_mode": "form", + "res_model": "account.move", + "res_id": self.accrual_move_id.id, + } + + has_assets = fields.Boolean(compute="_compute_has_assets") + + @api.depends("invoice_line_ids", "accrual_date") + def _compute_has_assets(self): + for rec in self: + if rec.accrual_date and rec.accrual_move_id: + line = rec.invoice_line_ids.filtered( + lambda x: x.accrual_account_id.user_type_id + == rec._get_accrual_asset_account_type_id() + ) + rec.has_assets = len(line) >= 1 and rec.accrual_date + else: + rec.has_assets = False + + @api.onchange("accrual_date") + def _onchange_accrual_date(self): + for rec in self: + for line in rec.invoice_line_ids: + if rec.accrual_date: + if ( + not line.accrual_account_id + and line.account_id != rec._get_accrual_account_id() + ): + line.accrual_account_id = line.account_id + line.account_id = rec._get_accrual_account_id() + else: + line.account_id = line.accrual_account_id + line.accrual_account_id = False + + @api.constrains("accrual_date", "date") + def _check_accrual_consistency(self): + if self.accrual_date: + if self.accrual_date > self.date: + raise ValidationError( + _( + "The accrual date cannot be greater than the date of the journal entry" + ) + ) + + @api.model_create_multi + def create(self, vals_list): + res = super(AccountMove, self).create(vals_list) + for rec in res: + if rec.accrual_date: + rec.invoice_line_ids.accrual_date = rec.accrual_date + return res + + def write(self, vals): + res = super(AccountMove, self).write(vals) + for rec in self: + for line in rec.invoice_line_ids: + if rec.accrual_date: + line.accrual_date = rec.accrual_date + else: + if "accrual_date" in vals: + line.accrual_date = False + return res + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + accrual_account_id = fields.Many2one( + comodel_name="account.account", + string="Accrual Account", + ) + + accrual_date = fields.Date(related="move_id.accrual_date", readonly=True) + + @api.onchange("product_id") + def _onchange_product_id(self): + for line in self: + super(AccountMoveLine, line)._onchange_product_id() + if line.move_id.accrual_date: + if not line.accrual_account_id: + line.accrual_account_id = line.account_id + else: + line.accrual_account_id = super( + AccountMoveLine, line + )._get_computed_account() + line.move_id._get_accrual_account_id() + line.account_id = self.env.company.accrual_account_id + else: + line.accrual_account_id = False + + def _set_accrual_account(self): + if not self.product_id: + return False + else: + return self._get_computed_account() + + @api.model_create_multi + def create(self, vals_list): + res = super(AccountMoveLine, self).create(vals_list) + for rec in res.filtered(lambda x: x in x.move_id.invoice_line_ids): + accrual_date = rec.move_id.accrual_date + if accrual_date: + accrual_account_id = rec.accrual_account_id + if not accrual_account_id: + accrual_account_id = rec.account_id + if rec.accrual_account_id == rec.move_id._get_accrual_account_id(): + accrual_account_id = rec._set_accrual_account() + if accrual_account_id: + rec.accrual_account_id = accrual_account_id.id + rec.account_id = rec.move_id._get_accrual_account_id().id + else: + setting_accrual_account_id = rec.move_id._get_accrual_account_id() + if setting_accrual_account_id: + if rec.account_id.id == setting_accrual_account_id.id: + if not rec.product_id: + raise UserError( + _("You cannot create %s with this account %s") + % (rec.name, rec.account_id.name) + ) + else: + rec.account_id = rec._get_computed_account() + return res + + def write(self, vals): + non_invoice_line_ids = self.filtered( + lambda x: x not in self.move_id.invoice_line_ids + ) + invoice_line_ids = self.filtered(lambda x: x in self.move_id.invoice_line_ids) + required_vals = {"account_id", "accrual_account_id", "accrual_date"} + if not any(val in required_vals for val in vals): + res = super(AccountMoveLine, self).write(vals) + else: + super(AccountMoveLine, non_invoice_line_ids).write(vals) + res = True + for rec in invoice_line_ids: + line_vals = {} + accrual_date = vals.get("accrual_date", rec.move_id.accrual_date) + accrual_account_id = vals.get( + "accrual_account_id", rec.accrual_account_id.id + ) + if accrual_date: + if ( + not accrual_account_id + and rec.account_id != rec.move_id._get_accrual_account_id() + ): + accrual_account_id = rec.account_id.id + if rec.accrual_account_id == rec.move_id._get_accrual_account_id(): + accrual_account_id = rec._set_accrual_account() + if accrual_account_id: + line_vals.update( + { + "accrual_account_id": accrual_account_id, + "account_id": vals.get( + "account_id", + rec.move_id._get_accrual_account_id().id, + ), + } + ) + elif accrual_account_id: + line_vals.update( + {"accrual_account_id": False, "account_id": accrual_account_id} + ) + else: + account_id = vals.get("account_id") + setting_accrual_account_id = rec.move_id._get_accrual_account_id() + if setting_accrual_account_id: + if account_id == setting_accrual_account_id.id: + line_vals.update({"account_id": rec.account_id.id}) + res &= super(AccountMoveLine, rec).write({**vals, **line_vals}) + return res diff --git a/account_move_accrual_entry/models/res_company.py b/account_move_accrual_entry/models/res_company.py new file mode 100644 index 000000000..242512ff8 --- /dev/null +++ b/account_move_accrual_entry/models/res_company.py @@ -0,0 +1,15 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from odoo import fields, models + + +class Company(models.Model): + _inherit = "res.company" + + accrual_account_id = fields.Many2one( + comodel_name="account.account", string="Accrual Account" + ) + + accrual_asset_account_type_id = fields.Many2one( + comodel_name="account.account.type", string="Account Type for Assets" + ) diff --git a/account_move_accrual_entry/models/res_config_settings.py b/account_move_accrual_entry/models/res_config_settings.py new file mode 100644 index 000000000..0bc82f551 --- /dev/null +++ b/account_move_accrual_entry/models/res_config_settings.py @@ -0,0 +1,28 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + accrual_account_id = fields.Many2one( + comodel_name="account.account", + string="Accrual Account", + related="company_id.accrual_account_id", + readonly=False, + domain=[ + ("reconcile", "=", True), + ("deprecated", "=", False), + ("user_type_id.type", "not in", ("receivable", "payable")), + ("is_off_balance", "=", False), + ], + ) + + accrual_asset_account_type_id = fields.Many2one( + comodel_name="account.account.type", + string="Account Type for Assets", + related="company_id.accrual_asset_account_type_id", + readonly=False, + domain=[("internal_group", "=", "asset")], + ) diff --git a/account_move_accrual_entry/readme/CONFIGURE.rst b/account_move_accrual_entry/readme/CONFIGURE.rst new file mode 100644 index 000000000..5c899df80 --- /dev/null +++ b/account_move_accrual_entry/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +To configure this module, you need to go to invoice settings and set the following parameters: + +* Default accrual account +* Default accrual asset account type diff --git a/account_move_accrual_entry/readme/CONTRIBUTORS.rst b/account_move_accrual_entry/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..b5c0d2df9 --- /dev/null +++ b/account_move_accrual_entry/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `NuoBiT `_: + + * Frank Cespedes + * Eric Antones diff --git a/account_move_accrual_entry/readme/DESCRIPTION.rst b/account_move_accrual_entry/readme/DESCRIPTION.rst new file mode 100644 index 000000000..42bd400fd --- /dev/null +++ b/account_move_accrual_entry/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module creates a journal entry at accrual date and adds a smart-button in the invoice to access it diff --git a/account_move_accrual_entry/static/description/icon.png b/account_move_accrual_entry/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cd641e792c30455187ca30940bc0f329ce8bbb0 GIT binary patch literal 6342 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 literal 0 HcmV?d00001 diff --git a/account_move_accrual_entry/static/description/index.html b/account_move_accrual_entry/static/description/index.html new file mode 100644 index 000000000..d772aec00 --- /dev/null +++ b/account_move_accrual_entry/static/description/index.html @@ -0,0 +1,430 @@ + + + + + + +Accrual Journal Entry + + + +
+

Accrual Journal Entry

+ + +

Beta License: AGPL-3 nuobit/odoo-addons

+

This module creates a journal entry at accrual date and adds a smart-button in the invoice to access it

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to go to invoice settings and set the following parameters:

+
    +
  • Default accrual account
  • +
  • Default accrual asset account type
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • NuoBiT Solutions
  • +
  • S.L.
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

Current maintainers:

+

FrankC013 eantones

+

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

+

You are welcome to contribute.

+
+
+
+ + diff --git a/account_move_accrual_entry/tests/__init__.py b/account_move_accrual_entry/tests/__init__.py new file mode 100644 index 000000000..a2913c0ad --- /dev/null +++ b/account_move_accrual_entry/tests/__init__.py @@ -0,0 +1,5 @@ +# Copyright NuoBiT Solutions, S.L. () +# Eric Antones +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import test_account diff --git a/account_move_accrual_entry/tests/common.py b/account_move_accrual_entry/tests/common.py new file mode 100644 index 000000000..1c21e8ea7 --- /dev/null +++ b/account_move_accrual_entry/tests/common.py @@ -0,0 +1,83 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from datetime import datetime + +from odoo.tests.common import SavepointCase + + +class CommonAccountMultiVat(SavepointCase): + @classmethod + def setUpClass(cls): + super(CommonAccountMultiVat, cls).setUpClass() + + # MODELS + cls.user_type = cls.env.ref("account.data_account_type_current_assets") + cls.journal = cls.env["account.journal"].create( + { + "name": "Customer Invoices 2", + "type": "sale", + "code": "test_INV2", + } + ) + cls.date = datetime.strptime("2022-01-13", "%Y-%m-%d").date() + cls.account_100 = cls.env["account.account"].create( + { + "name": "Test Account 100", + "code": "test_100000", + "user_type_id": cls.user_type.id, + } + ) + cls.account_empty = cls.env["account.account"] + cls.account_7000 = cls.env["account.account"].create( + { + "name": "Test Account 7000", + "code": "test_700000", + "user_type_id": cls.user_type.id, + } + ) + cls.tax_sale = cls.env["account.tax"].create( + {"name": "Sale tax", "type_tax_use": "sale", "amount": "20.00"} + ) + cls.account_205 = cls.env["account.account"].create( + { + "name": "Test Account 2050", + "code": "test_205000", + "user_type_id": cls.user_type.id, + } + ) + cls.accrual_account_id = cls.env["account.account"].create( + { + "name": "Test Account 4309", + "code": "test_430902", + "user_type_id": cls.user_type.id, + } + ) + cls.setting = cls.env["res.config.settings"].create( + { + "accrual_account_id": cls.accrual_account_id.id, + "accrual_asset_account_type_id": cls.env.ref( + "account.data_account_type_fixed_assets" + ).id, + } + ) + cls.product_template_205 = cls.env["product.template"].create( + { + "name": "New Product 205", + "type": "service", + "property_account_income_id": cls.account_205.id, + "taxes_id": [(6, 0, [cls.tax_sale.id])], + "lst_price": "100", + } + ) + cls.product_template_7000 = cls.env["product.template"].create( + { + "name": "New Product 7000", + "type": "service", + "property_account_income_id": cls.account_7000.id, + "taxes_id": [(6, 0, [cls.tax_sale.id])], + "lst_price": "100", + } + ) + cls.product_205 = cls.product_template_205.product_variant_id + cls.product_7000 = cls.product_template_7000.product_variant_id diff --git a/account_move_accrual_entry/tests/test_account.py b/account_move_accrual_entry/tests/test_account.py new file mode 100644 index 000000000..e18048928 --- /dev/null +++ b/account_move_accrual_entry/tests/test_account.py @@ -0,0 +1,296 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from . import common + +_logger = logging.getLogger(__name__) + + +class TestInvoice(common.CommonAccountMultiVat): + # TEST CREATE ACCOUNT.MOVE + def test_create_account_move(self): + def create_acrrual_invoice(self): + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + "move_type": "out_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_7000.id, + }, + ) + ], + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_7000, self.accrual_account_id), + ) + + create_acrrual_invoice(self) + + # TEST WRITE ACCOUNT.MOVE + def test_write_account_move(self): + def write_accrual_date_in_invoice(self): + # + # Create invoice without accrual date + # Write accrual date in invoice + # + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "move_type": "out_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_7000.id, + }, + ) + ], + } + ) + invoice.write( + { + "accrual_date": self.date, + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_7000, self.accrual_account_id), + ) + + write_accrual_date_in_invoice(self) + + def accrual_invoice_to_normal_invoice(self): + # CREATE & WRITE (ACCOUNT.MOVE) + # + # Create invoice with accrual date + # Write False in accrual date + # + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + "move_type": "out_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_7000.id, + }, + ) + ], + } + ) + invoice.write( + { + "accrual_date": False, + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_empty, self.account_7000), + ) + + accrual_invoice_to_normal_invoice(self) + + def accrual_invoice_to_normal_modifying_accrual_account(self): + # CREATE & WRITE (ACCOUNT.MOVE) + # + # Create invoice with accrual date + # Write False in accrual date & modify accrual account + # + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + "move_type": "out_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_7000.id, + }, + ) + ], + } + ) + invoice.write( + { + "accrual_date": False, + "invoice_line_ids": [ + ( + 1, + invoice.invoice_line_ids[0].id, + { + "accrual_account_id": self.account_100.id, + }, + ) + ], + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_empty, self.account_100), + ) + + accrual_invoice_to_normal_modifying_accrual_account(self) + + # TEST CREATE ACCOUNT.MOVE.LINE + def test_create_account_move_line(self): + def create_1_new_invoice_line(self): + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + "move_type": "out_invoice", + } + ) + self.env["account.move.line"].create( + { + "move_id": invoice.id, + "account_id": self.account_7000.id, + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_7000, self.accrual_account_id), + ) + + create_1_new_invoice_line(self) + + def create_2_new_invoice_line(self): + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + } + ) + self.env["account.move.line"].create( + [ + { + "move_id": invoice.id, + "account_id": self.account_7000.id, + }, + { + "move_id": invoice.id, + "account_id": self.account_100.id, + }, + ] + ) + + line = invoice.invoice_line_ids[0] + line1 = invoice.invoice_line_ids[1] + self.assertTupleEqual( + ( + line.accrual_account_id, + line.account_id, + line1.accrual_account_id, + line1.account_id, + ), + ( + self.account_7000, + self.accrual_account_id, + self.account_100, + self.accrual_account_id, + ), + ) + + create_2_new_invoice_line(self) + + def create_2_separate_new_invoice_line(self): + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + } + ) + self.env["account.move.line"].create( + { + "move_id": invoice.id, + "account_id": self.account_7000.id, + } + ) + self.env["account.move.line"].create( + { + "move_id": invoice.id, + "account_id": self.account_100.id, + } + ) + + line = invoice.invoice_line_ids[0] + line1 = invoice.invoice_line_ids[1] + self.assertTupleEqual( + ( + line.accrual_account_id, + line.account_id, + line1.accrual_account_id, + line1.account_id, + ), + ( + self.account_7000, + self.accrual_account_id, + self.account_100, + self.accrual_account_id, + ), + ) + + create_2_separate_new_invoice_line(self) + + # TEST WRITE ACCOUNT.MOVE.LINE + def test_write_account_move_line(self): + def write_accrual_account_invoice(self): + # + # Create invoice with accrual date + # Write accrual account in invoice line + # + invoice = self.env["account.move"].create( + { + "journal_id": self.journal.id, + "accrual_date": self.date, + "move_type": "out_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_7000.id, + }, + ) + ], + } + ) + invoice.invoice_line_ids.write( + { + "move_id": invoice.id, + "accrual_account_id": self.account_100.id, + } + ) + + line = invoice.invoice_line_ids[0] + self.assertTupleEqual( + (line.accrual_account_id, line.account_id), + (self.account_100, self.accrual_account_id), + ) + + write_accrual_account_invoice(self) diff --git a/account_move_accrual_entry/views/account_move_views.xml b/account_move_accrual_entry/views/account_move_views.xml new file mode 100644 index 000000000..7bb388131 --- /dev/null +++ b/account_move_accrual_entry/views/account_move_views.xml @@ -0,0 +1,80 @@ + + + + + account.move.form.sii + account.move + + + + + + + + +
+ +
+ + + + + + + + + + {'required': [('display_type', '=', False)], 'readonly': [('accrual_date', '!=', False)]} + +
+
+
diff --git a/account_move_accrual_entry/views/res_config_settings_views.xml b/account_move_accrual_entry/views/res_config_settings_views.xml new file mode 100644 index 000000000..6a4faf2e8 --- /dev/null +++ b/account_move_accrual_entry/views/res_config_settings_views.xml @@ -0,0 +1,48 @@ + + + + + res.config.settings.form.inherit.account.sii + res.config.settings + + + +
+
+
+ Accrual Parameters + +
+ Accrual parameters used on sale invoices +
+
+
+
+
+
+
+
+
+ + + + From 0a7b479afcb0ea78bca573cfb2eccfd3030068ab Mon Sep 17 00:00:00 2001 From: Eric Antones Date: Tue, 16 May 2023 18:51:40 +0200 Subject: [PATCH 2/8] [REF+IMP] account_move_accrual_entry: Various refactors and improvements --- account_move_accrual_entry/i18n/es.po | 120 +++++-- account_move_accrual_entry/models/__init__.py | 1 + .../models/account_move.py | 293 +++++------------ .../models/account_move_line.py | 31 ++ .../models/res_company.py | 8 +- .../models/res_config_settings.py | 7 +- account_move_accrual_entry/tests/__init__.py | 5 - account_move_accrual_entry/tests/common.py | 83 ----- .../tests/test_account.py | 296 ------------------ .../views/account_move_views.xml | 25 +- .../views/res_config_settings_views.xml | 5 +- 11 files changed, 229 insertions(+), 645 deletions(-) create mode 100644 account_move_accrual_entry/models/account_move_line.py delete mode 100644 account_move_accrual_entry/tests/__init__.py delete mode 100644 account_move_accrual_entry/tests/common.py delete mode 100644 account_move_accrual_entry/tests/test_account.py diff --git a/account_move_accrual_entry/i18n/es.po b/account_move_accrual_entry/i18n/es.po index b2c568eb9..d48e3f902 100644 --- a/account_move_accrual_entry/i18n/es.po +++ b/account_move_accrual_entry/i18n/es.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 10:58+0000\n" -"PO-Revision-Date: 2023-04-27 10:58+0000\n" +"POT-Creation-Date: 2023-05-16 16:31+0000\n" +"PO-Revision-Date: 2023-05-16 16:31+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -30,17 +30,10 @@ msgid "Accrual entry" msgstr "Asiento Periodif." #. module: account_move_accrual_entry -#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__account_id #: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii msgid "Account" msgstr "Cuenta" -#. module: account_move_accrual_entry -#: code:addons/account_move_accrual_entry/models/account_move.py:0 -#, python-format -msgid "The accrual date cannot be greater than the date of the journal entry" -msgstr "La fecha de periodificación no puede ser posterior a la fecha de la factura" - #. module: account_move_accrual_entry #: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__accrual_account_id #: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__accrual_account_id @@ -48,6 +41,12 @@ msgstr "La fecha de periodificación no puede ser posterior a la fecha de la fac msgid "Accrual Account" msgstr "Cuenta de periodificación" +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__accrual_account_asset_type_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__accrual_account_asset_type_id +msgid "Accrual Account Asset Type" +msgstr "Tipo de cuenta de activo" + #. module: account_move_accrual_entry #: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_bank_statement_line__accrual_date #: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__accrual_date @@ -59,13 +58,20 @@ msgstr "Fecha de periodificación" #. module: account_move_accrual_entry #: code:addons/account_move_accrual_entry/models/account_move.py:0 #, python-format -msgid "You cannot create %s with this account %s" -msgstr "No puedes crear %s con esta cuenta %s" +msgid "Accrual Journal Entry" +msgstr "Asiento de periodificación" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_bank_statement_line__accrual_move_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__accrual_move_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_payment__accrual_move_id +msgid "Accrual Move" +msgstr "" #. module: account_move_accrual_entry #: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii msgid "Accrual parameters used on sale invoices" -msgstr "Parametros de periodificación usados en facturas de venta" +msgstr "Parámetros de periodificación usados en facturas de venta" #. module: account_move_accrual_entry #: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii @@ -73,30 +79,90 @@ msgid "Asset account type" msgstr "Tipo de cuenta de activo" #. module: account_move_accrual_entry -#: code:addons/account_move_accrual_entry/models/account_move.py:0 -#, python-format -msgid "Journal entry with accrual date for assets not allowed." -msgstr "Asiento contable con fecha de periodificación para activos no permitido." +#: model:ir.model,name:account_move_accrual_entry.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_bank_statement_line__company_accrual_account_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__company_accrual_account_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_payment__company_accrual_account_id +msgid "Company Accrual Account" +msgstr "" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_bank_statement_line__company_accrual_account_asset_type_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__company_accrual_account_asset_type_id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_payment__company_accrual_account_asset_type_id +msgid "Company Accrual Account Asset Type" +msgstr "" + +#. module: account_move_accrual_entry +#: model:ir.model,name:account_move_accrual_entry.model_res_config_settings +msgid "Config Settings" +msgstr "Opciones de configuración" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__display_name +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__display_name +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__display_name +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move__id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line__id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__id +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__id +msgid "ID" +msgstr "" #. module: account_move_accrual_entry #: code:addons/account_move_accrual_entry/models/account_move.py:0 #, python-format -msgid "Please set the accrual account in the invoincing settings." -msgstr "Por favor, establezca la cuenta de periodificación en la configuración de facturación." +msgid "" +"It's not allowed to create an Accrual Journal Entry if there's assets in the" +" invoice" +msgstr "No está permitido crear el asiento de periodificación si la factura contiene activos" + +#. module: account_move_accrual_entry +#: model:ir.model,name:account_move_accrual_entry.model_account_move +msgid "Journal Entry" +msgstr "Asiento contable" + +#. module: account_move_accrual_entry +#: model:ir.model,name:account_move_accrual_entry.model_account_move_line +msgid "Journal Item" +msgstr "Apunte contable" + +#. module: account_move_accrual_entry +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move____last_update +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_account_move_line____last_update +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company____last_update +#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings____last_update +msgid "Last Modified on" +msgstr "Última modificación el" #. module: account_move_accrual_entry #: code:addons/account_move_accrual_entry/models/account_move.py:0 #, python-format -msgid "Please set the account type for assets in the invoincing settings." -msgstr "Por favor, establezca el tipo de cuenta para activos en la configuración de facturación." +msgid "Please set the account type for assets in the invoicing settings." +msgstr "" +"Por favor, establezca el tipo de cuenta para activos en la configuración de " +"facturación." #. module: account_move_accrual_entry -#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_config_settings__accrual_asset_account_type_id -#: model:ir.model.fields,field_description:account_move_accrual_entry.field_res_company__accrual_asset_account_type_id -msgid "Account Type for Assets" -msgstr "Tipo de cuenta para activos" +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "Please set the accrual account in the invoicing settings." +msgstr "" +"Por favor, establezca la cuenta de periodificación en la configuración de " +"facturación." #. module: account_move_accrual_entry -#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.view_move_form -msgid "You have assets added to the invoice" -msgstr "Tienes activos añadidos en la factura" +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "The accrual date must be prior to the invoice date" +msgstr "" +"La fecha de periodificación debe ser anterior a la fecha de la factura" diff --git a/account_move_accrual_entry/models/__init__.py b/account_move_accrual_entry/models/__init__.py index d710c036a..1c3a7bdd4 100644 --- a/account_move_accrual_entry/models/__init__.py +++ b/account_move_accrual_entry/models/__init__.py @@ -1,3 +1,4 @@ +from . import account_move_line from . import account_move from . import res_config_settings from . import res_company diff --git a/account_move_accrual_entry/models/account_move.py b/account_move_accrual_entry/models/account_move.py index 83c89cb90..af707e241 100644 --- a/account_move_accrual_entry/models/account_move.py +++ b/account_move_accrual_entry/models/account_move.py @@ -1,4 +1,5 @@ # Copyright NuoBiT Solutions - Frank Cespedes +# Copyright NuoBiT Solutions - Eric Antones # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError @@ -10,60 +11,95 @@ class AccountMove(models.Model): accrual_date = fields.Date(string="Accrual Date") accrual_move_id = fields.Many2one( comodel_name="account.move", - relation="accrual_account_move_rel", - column1="move_id", - column2="accrual_move_id", copy=False, readonly=True, ) - def _get_accrual_account_id(self): - if self.accrual_date: - if not self.env.company.accrual_account_id: - raise UserError( - _("Please set the accrual account in the invoincing settings.") - ) - return self.env.company.accrual_account_id + # auxiliar computed fields to simplify the validations and make the code clear + company_accrual_account_id = fields.Many2one( + comodel_name="account.account", + compute="_compute_company_accrual_account_id", + ) - def _get_accrual_asset_account_type_id(self): - if not self.env.company.accrual_asset_account_type_id: - raise UserError( - _("Please set the account type for assets in the invoincing settings.") - ) - return self.env.company.accrual_asset_account_type_id + @api.depends("company_id") + def _compute_company_accrual_account_id(self): + for rec in self: + if rec.move_type in ("out_invoice", "out_refund"): + accrual_account = rec.company_id.accrual_account_id + if rec.company_id and rec.accrual_date and not accrual_account: + raise UserError( + _("Please set the accrual account in the invoicing settings.") + ) + rec.company_accrual_account_id = accrual_account + else: + rec.company_accrual_account_id = False + + company_accrual_account_asset_type_id = fields.Many2one( + comodel_name="account.account.type", + compute="_compute_accrual_account_asset_type_id", + ) + + @api.depends("company_id") + def _compute_accrual_account_asset_type_id(self): + for rec in self: + if rec.move_type in ("out_invoice", "out_refund"): + accrual_account_asset_type = ( + rec.company_id.accrual_account_asset_type_id + ) + if rec.company_id and not accrual_account_asset_type: + raise UserError( + _( + "Please set the account type for assets in the invoicing settings." + ) + ) + rec.company_accrual_account_asset_type_id = accrual_account_asset_type + else: + rec.company_accrual_account_asset_type_id = False - def _not_asset(self, x): - asset = self.env.company.accrual_asset_account_type_id - return x.accrual_account_id.user_type_id != asset + @api.onchange("accrual_date") + def _onchange_accrual_date(self): + for rec in self: + for line in rec.invoice_line_ids: + if rec.move_type in ("out_invoice", "out_refund") and rec.accrual_date: + if ( + not line.accrual_account_id + and line.account_id != rec.company_accrual_account_id + ): + line.accrual_account_id = line.account_id + line.account_id = rec.company_accrual_account_id + else: + line.account_id = line.accrual_account_id + line.accrual_account_id = False - def _asset(self, x): - asset = self.env.company.accrual_asset_account_type_id - return x.accrual_account_id.user_type_id == asset + @api.constrains("accrual_date", "date", "move_type") + def _check_accrual_consistency(self): + for rec in self: + if ( + rec.move_type in ("out_invoice", "out_refund") + and rec.accrual_date + and rec.accrual_date >= rec.date + ): + raise ValidationError( + _("The accrual date must be prior to the invoice date") + ) def _accrual_reconcile(self, rec): - invoice_line_ids = self.invoice_line_ids.filtered( - lambda x: x.accrual_account_id.user_type_id - != self._get_accrual_asset_account_type_id() - ) - for l0, l1 in zip(invoice_line_ids, rec.line_ids): + for l0, l1 in zip(self.invoice_line_ids, rec.line_ids): (l0 | l1).reconcile() def _prepare_lines(self): line_ids = [] - non_asset_invoice_lines = self.invoice_line_ids.filtered( - lambda x: x.accrual_account_id.user_type_id - != self._get_accrual_asset_account_type_id() - ) for idx in range(2): - for line in non_asset_invoice_lines: + for line in self.invoice_line_ids: ji = { "name": line.name, "date": self.accrual_date, + "partner_id": line.partner_id.id, "account_id": line.account_id.id if idx == 0 else line.accrual_account_id.id, - "debit": line.price_subtotal if idx == 0 else 0, - "credit": 0 if idx == 0 else line.price_subtotal, + "debit": line.credit if idx == 0 else line.debit, + "credit": line.debit if idx == 0 else line.credit, } line_ids.append(ji) return line_ids @@ -72,9 +108,9 @@ def _create_accrual_move(self): line_ids = [(0, 0, line_dict) for line_dict in self._prepare_lines()] return self.env[self._name].create( { + "company_id": self.company_id.id, "partner_id": self.partner_id.id, "journal_id": self.journal_id.id, - "accrual_date": self.accrual_date, "date": self.accrual_date, "move_type": "entry", "line_ids": line_ids, @@ -84,11 +120,17 @@ def _create_accrual_move(self): def _post(self, soft=True): res = super(AccountMove, self)._post(soft=soft) for rec in self: - if rec.accrual_date: - non_asset_lines = rec.invoice_line_ids.filtered(rec._not_asset) - if rec.invoice_line_ids and not non_asset_lines: + if rec.move_type in ("out_invoice", "out_refund") and rec.accrual_date: + asset_lines = rec.invoice_line_ids.filtered( + lambda x: x.accrual_account_id.user_type_id + == self.company_accrual_account_asset_type_id + ) + if asset_lines: raise UserError( - _("Journal entry with accrual date for assets not allowed.") + _( + "It's not allowed to create an Accrual Journal Entry " + "if there's assets in the invoice" + ) ) accrual_move = rec._create_accrual_move() super(AccountMove, accrual_move)._post(soft=False) @@ -98,181 +140,16 @@ def _post(self, soft=True): def button_draft(self): super().button_draft() - super(AccountMove, self.accrual_move_id).button_draft() - self.accrual_move_id.with_context(force_delete=True).unlink() + if self.accrual_move_id: + super(AccountMove, self.accrual_move_id).button_draft() + self.accrual_move_id.with_context(force_delete=True).unlink() def action_journal_entry(self): self.ensure_one() return { - "name": "Accruals assets", + "name": _("Accrual Journal Entry"), "type": "ir.actions.act_window", "view_mode": "form", "res_model": "account.move", "res_id": self.accrual_move_id.id, } - - has_assets = fields.Boolean(compute="_compute_has_assets") - - @api.depends("invoice_line_ids", "accrual_date") - def _compute_has_assets(self): - for rec in self: - if rec.accrual_date and rec.accrual_move_id: - line = rec.invoice_line_ids.filtered( - lambda x: x.accrual_account_id.user_type_id - == rec._get_accrual_asset_account_type_id() - ) - rec.has_assets = len(line) >= 1 and rec.accrual_date - else: - rec.has_assets = False - - @api.onchange("accrual_date") - def _onchange_accrual_date(self): - for rec in self: - for line in rec.invoice_line_ids: - if rec.accrual_date: - if ( - not line.accrual_account_id - and line.account_id != rec._get_accrual_account_id() - ): - line.accrual_account_id = line.account_id - line.account_id = rec._get_accrual_account_id() - else: - line.account_id = line.accrual_account_id - line.accrual_account_id = False - - @api.constrains("accrual_date", "date") - def _check_accrual_consistency(self): - if self.accrual_date: - if self.accrual_date > self.date: - raise ValidationError( - _( - "The accrual date cannot be greater than the date of the journal entry" - ) - ) - - @api.model_create_multi - def create(self, vals_list): - res = super(AccountMove, self).create(vals_list) - for rec in res: - if rec.accrual_date: - rec.invoice_line_ids.accrual_date = rec.accrual_date - return res - - def write(self, vals): - res = super(AccountMove, self).write(vals) - for rec in self: - for line in rec.invoice_line_ids: - if rec.accrual_date: - line.accrual_date = rec.accrual_date - else: - if "accrual_date" in vals: - line.accrual_date = False - return res - - -class AccountMoveLine(models.Model): - _inherit = "account.move.line" - - accrual_account_id = fields.Many2one( - comodel_name="account.account", - string="Accrual Account", - ) - - accrual_date = fields.Date(related="move_id.accrual_date", readonly=True) - - @api.onchange("product_id") - def _onchange_product_id(self): - for line in self: - super(AccountMoveLine, line)._onchange_product_id() - if line.move_id.accrual_date: - if not line.accrual_account_id: - line.accrual_account_id = line.account_id - else: - line.accrual_account_id = super( - AccountMoveLine, line - )._get_computed_account() - line.move_id._get_accrual_account_id() - line.account_id = self.env.company.accrual_account_id - else: - line.accrual_account_id = False - - def _set_accrual_account(self): - if not self.product_id: - return False - else: - return self._get_computed_account() - - @api.model_create_multi - def create(self, vals_list): - res = super(AccountMoveLine, self).create(vals_list) - for rec in res.filtered(lambda x: x in x.move_id.invoice_line_ids): - accrual_date = rec.move_id.accrual_date - if accrual_date: - accrual_account_id = rec.accrual_account_id - if not accrual_account_id: - accrual_account_id = rec.account_id - if rec.accrual_account_id == rec.move_id._get_accrual_account_id(): - accrual_account_id = rec._set_accrual_account() - if accrual_account_id: - rec.accrual_account_id = accrual_account_id.id - rec.account_id = rec.move_id._get_accrual_account_id().id - else: - setting_accrual_account_id = rec.move_id._get_accrual_account_id() - if setting_accrual_account_id: - if rec.account_id.id == setting_accrual_account_id.id: - if not rec.product_id: - raise UserError( - _("You cannot create %s with this account %s") - % (rec.name, rec.account_id.name) - ) - else: - rec.account_id = rec._get_computed_account() - return res - - def write(self, vals): - non_invoice_line_ids = self.filtered( - lambda x: x not in self.move_id.invoice_line_ids - ) - invoice_line_ids = self.filtered(lambda x: x in self.move_id.invoice_line_ids) - required_vals = {"account_id", "accrual_account_id", "accrual_date"} - if not any(val in required_vals for val in vals): - res = super(AccountMoveLine, self).write(vals) - else: - super(AccountMoveLine, non_invoice_line_ids).write(vals) - res = True - for rec in invoice_line_ids: - line_vals = {} - accrual_date = vals.get("accrual_date", rec.move_id.accrual_date) - accrual_account_id = vals.get( - "accrual_account_id", rec.accrual_account_id.id - ) - if accrual_date: - if ( - not accrual_account_id - and rec.account_id != rec.move_id._get_accrual_account_id() - ): - accrual_account_id = rec.account_id.id - if rec.accrual_account_id == rec.move_id._get_accrual_account_id(): - accrual_account_id = rec._set_accrual_account() - if accrual_account_id: - line_vals.update( - { - "accrual_account_id": accrual_account_id, - "account_id": vals.get( - "account_id", - rec.move_id._get_accrual_account_id().id, - ), - } - ) - elif accrual_account_id: - line_vals.update( - {"accrual_account_id": False, "account_id": accrual_account_id} - ) - else: - account_id = vals.get("account_id") - setting_accrual_account_id = rec.move_id._get_accrual_account_id() - if setting_accrual_account_id: - if account_id == setting_accrual_account_id.id: - line_vals.update({"account_id": rec.account_id.id}) - res &= super(AccountMoveLine, rec).write({**vals, **line_vals}) - return res diff --git a/account_move_accrual_entry/models/account_move_line.py b/account_move_accrual_entry/models/account_move_line.py new file mode 100644 index 000000000..c16812197 --- /dev/null +++ b/account_move_accrual_entry/models/account_move_line.py @@ -0,0 +1,31 @@ +# Copyright NuoBiT Solutions - Frank Cespedes +# Copyright NuoBiT Solutions - Eric Antones +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from odoo import api, fields, models + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + accrual_date = fields.Date(related="move_id.accrual_date", readonly=True) + accrual_account_id = fields.Many2one( + comodel_name="account.account", + string="Accrual Account", + ) + + @api.onchange("account_id") + def _onchange_accrual_entry_account_id(self): + for line in self: + if ( + line.move_id.move_type in ("out_invoice", "out_refund") + and line.move_id.accrual_date + ): + if not line.accrual_account_id: + line.accrual_account_id = line.account_id + else: + line.accrual_account_id = super( + AccountMoveLine, line + )._get_computed_account() + line.account_id = line.move_id.company_accrual_account_id + else: + line.accrual_account_id = False diff --git a/account_move_accrual_entry/models/res_company.py b/account_move_accrual_entry/models/res_company.py index 242512ff8..2f729de0c 100644 --- a/account_move_accrual_entry/models/res_company.py +++ b/account_move_accrual_entry/models/res_company.py @@ -1,4 +1,5 @@ # Copyright NuoBiT Solutions - Frank Cespedes +# Copyright NuoBiT Solutions - Eric Antones # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields, models @@ -7,9 +8,10 @@ class Company(models.Model): _inherit = "res.company" accrual_account_id = fields.Many2one( - comodel_name="account.account", string="Accrual Account" + comodel_name="account.account", ) - accrual_asset_account_type_id = fields.Many2one( - comodel_name="account.account.type", string="Account Type for Assets" + accrual_account_asset_type_id = fields.Many2one( + comodel_name="account.account.type", + default=lambda self: self.env.ref("account.data_account_type_fixed_assets"), ) diff --git a/account_move_accrual_entry/models/res_config_settings.py b/account_move_accrual_entry/models/res_config_settings.py index 0bc82f551..97aa162e3 100644 --- a/account_move_accrual_entry/models/res_config_settings.py +++ b/account_move_accrual_entry/models/res_config_settings.py @@ -1,4 +1,5 @@ # Copyright NuoBiT Solutions - Frank Cespedes +# Copyright NuoBiT Solutions - Eric Antones # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields, models @@ -8,7 +9,6 @@ class ResConfigSettings(models.TransientModel): accrual_account_id = fields.Many2one( comodel_name="account.account", - string="Accrual Account", related="company_id.accrual_account_id", readonly=False, domain=[ @@ -19,10 +19,9 @@ class ResConfigSettings(models.TransientModel): ], ) - accrual_asset_account_type_id = fields.Many2one( + accrual_account_asset_type_id = fields.Many2one( comodel_name="account.account.type", - string="Account Type for Assets", - related="company_id.accrual_asset_account_type_id", + related="company_id.accrual_account_asset_type_id", readonly=False, domain=[("internal_group", "=", "asset")], ) diff --git a/account_move_accrual_entry/tests/__init__.py b/account_move_accrual_entry/tests/__init__.py deleted file mode 100644 index a2913c0ad..000000000 --- a/account_move_accrual_entry/tests/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright NuoBiT Solutions, S.L. () -# Eric Antones -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -from . import test_account diff --git a/account_move_accrual_entry/tests/common.py b/account_move_accrual_entry/tests/common.py deleted file mode 100644 index 1c21e8ea7..000000000 --- a/account_move_accrual_entry/tests/common.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright NuoBiT Solutions - Frank Cespedes -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -from datetime import datetime - -from odoo.tests.common import SavepointCase - - -class CommonAccountMultiVat(SavepointCase): - @classmethod - def setUpClass(cls): - super(CommonAccountMultiVat, cls).setUpClass() - - # MODELS - cls.user_type = cls.env.ref("account.data_account_type_current_assets") - cls.journal = cls.env["account.journal"].create( - { - "name": "Customer Invoices 2", - "type": "sale", - "code": "test_INV2", - } - ) - cls.date = datetime.strptime("2022-01-13", "%Y-%m-%d").date() - cls.account_100 = cls.env["account.account"].create( - { - "name": "Test Account 100", - "code": "test_100000", - "user_type_id": cls.user_type.id, - } - ) - cls.account_empty = cls.env["account.account"] - cls.account_7000 = cls.env["account.account"].create( - { - "name": "Test Account 7000", - "code": "test_700000", - "user_type_id": cls.user_type.id, - } - ) - cls.tax_sale = cls.env["account.tax"].create( - {"name": "Sale tax", "type_tax_use": "sale", "amount": "20.00"} - ) - cls.account_205 = cls.env["account.account"].create( - { - "name": "Test Account 2050", - "code": "test_205000", - "user_type_id": cls.user_type.id, - } - ) - cls.accrual_account_id = cls.env["account.account"].create( - { - "name": "Test Account 4309", - "code": "test_430902", - "user_type_id": cls.user_type.id, - } - ) - cls.setting = cls.env["res.config.settings"].create( - { - "accrual_account_id": cls.accrual_account_id.id, - "accrual_asset_account_type_id": cls.env.ref( - "account.data_account_type_fixed_assets" - ).id, - } - ) - cls.product_template_205 = cls.env["product.template"].create( - { - "name": "New Product 205", - "type": "service", - "property_account_income_id": cls.account_205.id, - "taxes_id": [(6, 0, [cls.tax_sale.id])], - "lst_price": "100", - } - ) - cls.product_template_7000 = cls.env["product.template"].create( - { - "name": "New Product 7000", - "type": "service", - "property_account_income_id": cls.account_7000.id, - "taxes_id": [(6, 0, [cls.tax_sale.id])], - "lst_price": "100", - } - ) - cls.product_205 = cls.product_template_205.product_variant_id - cls.product_7000 = cls.product_template_7000.product_variant_id diff --git a/account_move_accrual_entry/tests/test_account.py b/account_move_accrual_entry/tests/test_account.py deleted file mode 100644 index e18048928..000000000 --- a/account_move_accrual_entry/tests/test_account.py +++ /dev/null @@ -1,296 +0,0 @@ -# Copyright NuoBiT Solutions - Frank Cespedes -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from . import common - -_logger = logging.getLogger(__name__) - - -class TestInvoice(common.CommonAccountMultiVat): - # TEST CREATE ACCOUNT.MOVE - def test_create_account_move(self): - def create_acrrual_invoice(self): - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - "move_type": "out_invoice", - "invoice_line_ids": [ - ( - 0, - 0, - { - "account_id": self.account_7000.id, - }, - ) - ], - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_7000, self.accrual_account_id), - ) - - create_acrrual_invoice(self) - - # TEST WRITE ACCOUNT.MOVE - def test_write_account_move(self): - def write_accrual_date_in_invoice(self): - # - # Create invoice without accrual date - # Write accrual date in invoice - # - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "move_type": "out_invoice", - "invoice_line_ids": [ - ( - 0, - 0, - { - "account_id": self.account_7000.id, - }, - ) - ], - } - ) - invoice.write( - { - "accrual_date": self.date, - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_7000, self.accrual_account_id), - ) - - write_accrual_date_in_invoice(self) - - def accrual_invoice_to_normal_invoice(self): - # CREATE & WRITE (ACCOUNT.MOVE) - # - # Create invoice with accrual date - # Write False in accrual date - # - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - "move_type": "out_invoice", - "invoice_line_ids": [ - ( - 0, - 0, - { - "account_id": self.account_7000.id, - }, - ) - ], - } - ) - invoice.write( - { - "accrual_date": False, - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_empty, self.account_7000), - ) - - accrual_invoice_to_normal_invoice(self) - - def accrual_invoice_to_normal_modifying_accrual_account(self): - # CREATE & WRITE (ACCOUNT.MOVE) - # - # Create invoice with accrual date - # Write False in accrual date & modify accrual account - # - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - "move_type": "out_invoice", - "invoice_line_ids": [ - ( - 0, - 0, - { - "account_id": self.account_7000.id, - }, - ) - ], - } - ) - invoice.write( - { - "accrual_date": False, - "invoice_line_ids": [ - ( - 1, - invoice.invoice_line_ids[0].id, - { - "accrual_account_id": self.account_100.id, - }, - ) - ], - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_empty, self.account_100), - ) - - accrual_invoice_to_normal_modifying_accrual_account(self) - - # TEST CREATE ACCOUNT.MOVE.LINE - def test_create_account_move_line(self): - def create_1_new_invoice_line(self): - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - "move_type": "out_invoice", - } - ) - self.env["account.move.line"].create( - { - "move_id": invoice.id, - "account_id": self.account_7000.id, - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_7000, self.accrual_account_id), - ) - - create_1_new_invoice_line(self) - - def create_2_new_invoice_line(self): - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - } - ) - self.env["account.move.line"].create( - [ - { - "move_id": invoice.id, - "account_id": self.account_7000.id, - }, - { - "move_id": invoice.id, - "account_id": self.account_100.id, - }, - ] - ) - - line = invoice.invoice_line_ids[0] - line1 = invoice.invoice_line_ids[1] - self.assertTupleEqual( - ( - line.accrual_account_id, - line.account_id, - line1.accrual_account_id, - line1.account_id, - ), - ( - self.account_7000, - self.accrual_account_id, - self.account_100, - self.accrual_account_id, - ), - ) - - create_2_new_invoice_line(self) - - def create_2_separate_new_invoice_line(self): - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - } - ) - self.env["account.move.line"].create( - { - "move_id": invoice.id, - "account_id": self.account_7000.id, - } - ) - self.env["account.move.line"].create( - { - "move_id": invoice.id, - "account_id": self.account_100.id, - } - ) - - line = invoice.invoice_line_ids[0] - line1 = invoice.invoice_line_ids[1] - self.assertTupleEqual( - ( - line.accrual_account_id, - line.account_id, - line1.accrual_account_id, - line1.account_id, - ), - ( - self.account_7000, - self.accrual_account_id, - self.account_100, - self.accrual_account_id, - ), - ) - - create_2_separate_new_invoice_line(self) - - # TEST WRITE ACCOUNT.MOVE.LINE - def test_write_account_move_line(self): - def write_accrual_account_invoice(self): - # - # Create invoice with accrual date - # Write accrual account in invoice line - # - invoice = self.env["account.move"].create( - { - "journal_id": self.journal.id, - "accrual_date": self.date, - "move_type": "out_invoice", - "invoice_line_ids": [ - ( - 0, - 0, - { - "account_id": self.account_7000.id, - }, - ) - ], - } - ) - invoice.invoice_line_ids.write( - { - "move_id": invoice.id, - "accrual_account_id": self.account_100.id, - } - ) - - line = invoice.invoice_line_ids[0] - self.assertTupleEqual( - (line.accrual_account_id, line.account_id), - (self.account_100, self.accrual_account_id), - ) - - write_accrual_account_invoice(self) diff --git a/account_move_accrual_entry/views/account_move_views.xml b/account_move_accrual_entry/views/account_move_views.xml index 7bb388131..15c16aaf4 100644 --- a/account_move_accrual_entry/views/account_move_views.xml +++ b/account_move_accrual_entry/views/account_move_views.xml @@ -1,5 +1,6 @@ @@ -7,36 +8,26 @@ account.move - - -
+
From 8468153afe862f7f729e0b630f3c13c24235d161 Mon Sep 17 00:00:00 2001 From: Eric Antones Date: Mon, 29 May 2023 23:53:19 +0200 Subject: [PATCH 3/8] [IMP] account_move_accrual_entry: added journal to use on accrual entries --- account_move_accrual_entry/__manifest__.py | 3 ++- account_move_accrual_entry/i18n/es.po | 15 +++++++++++++- .../models/account_move.py | 20 ++++++++++++++++++- .../models/res_company.py | 12 +++++++++++ .../models/res_config_settings.py | 13 ++++++------ .../views/res_config_settings_views.xml | 8 ++++++++ 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/account_move_accrual_entry/__manifest__.py b/account_move_accrual_entry/__manifest__.py index 232e44fd4..59cd9b3c7 100644 --- a/account_move_accrual_entry/__manifest__.py +++ b/account_move_accrual_entry/__manifest__.py @@ -1,10 +1,11 @@ # Copyright NuoBiT Solutions, S.L. () # Frank Cespedes +# Eric Antones # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) { "name": "Accrual Journal Entry", "summary": "This module create journal entry with accrual date", - "version": "14.0.1.0.0", + "version": "14.0.1.0.1", "category": "Accounting", "author": "NuoBiT Solutions, S.L.", "website": "https://github.com/nuobit/odoo-addons", diff --git a/account_move_accrual_entry/i18n/es.po b/account_move_accrual_entry/i18n/es.po index d48e3f902..fe7673af0 100644 --- a/account_move_accrual_entry/i18n/es.po +++ b/account_move_accrual_entry/i18n/es.po @@ -21,7 +21,7 @@ msgid "" "Accrual Parameters\n" " " msgstr "" -"Parametros de periodificación\n" +"Parámetros de periodificación\n" " " #. module: account_move_accrual_entry @@ -73,6 +73,11 @@ msgstr "" msgid "Accrual parameters used on sale invoices" msgstr "Parámetros de periodificación usados en facturas de venta" +#. module: account_move_accrual_entry +#: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii +msgid "Journal" +msgstr "Diario" + #. module: account_move_accrual_entry #: model_terms:ir.ui.view,arch_db:account_move_accrual_entry.res_config_settings_view_form_inherit_account_sii msgid "Asset account type" @@ -152,6 +157,14 @@ msgstr "" "Por favor, establezca el tipo de cuenta para activos en la configuración de " "facturación." +#. module: account_move_accrual_entry +#: code:addons/account_move_accrual_entry/models/account_move.py:0 +#, python-format +msgid "Please set the accrual journal in the invoicing settings." +msgstr "" +"Por favor, establezca el diario de periodificación en la configuración de " +"facturación." + #. module: account_move_accrual_entry #: code:addons/account_move_accrual_entry/models/account_move.py:0 #, python-format diff --git a/account_move_accrual_entry/models/account_move.py b/account_move_accrual_entry/models/account_move.py index af707e241..29ccb5502 100644 --- a/account_move_accrual_entry/models/account_move.py +++ b/account_move_accrual_entry/models/account_move.py @@ -34,6 +34,24 @@ def _compute_company_accrual_account_id(self): else: rec.company_accrual_account_id = False + company_accrual_journal_id = fields.Many2one( + comodel_name="account.journal", + compute="_compute_company_accrual_journal_id", + ) + + @api.depends("company_id") + def _compute_company_accrual_journal_id(self): + for rec in self: + if rec.move_type in ("out_invoice", "out_refund"): + accrual_journal = rec.company_id.accrual_journal_id + if rec.company_id and rec.accrual_date and not accrual_journal: + raise UserError( + _("Please set the accrual journal in the invoicing settings.") + ) + rec.company_accrual_journal_id = accrual_journal + else: + rec.company_accrual_journal_id = False + company_accrual_account_asset_type_id = fields.Many2one( comodel_name="account.account.type", compute="_compute_accrual_account_asset_type_id", @@ -110,7 +128,7 @@ def _create_accrual_move(self): { "company_id": self.company_id.id, "partner_id": self.partner_id.id, - "journal_id": self.journal_id.id, + "journal_id": self.company_accrual_journal_id.id, "date": self.accrual_date, "move_type": "entry", "line_ids": line_ids, diff --git a/account_move_accrual_entry/models/res_company.py b/account_move_accrual_entry/models/res_company.py index 2f729de0c..3b33fecf2 100644 --- a/account_move_accrual_entry/models/res_company.py +++ b/account_move_accrual_entry/models/res_company.py @@ -9,9 +9,21 @@ class Company(models.Model): accrual_account_id = fields.Many2one( comodel_name="account.account", + domain=[ + ("reconcile", "=", True), + ("deprecated", "=", False), + ("user_type_id.type", "not in", ("receivable", "payable")), + ("is_off_balance", "=", False), + ], + ) + + accrual_journal_id = fields.Many2one( + comodel_name="account.journal", + domain=[("type", "=", "general")], ) accrual_account_asset_type_id = fields.Many2one( comodel_name="account.account.type", default=lambda self: self.env.ref("account.data_account_type_fixed_assets"), + domain=[("internal_group", "=", "asset")], ) diff --git a/account_move_accrual_entry/models/res_config_settings.py b/account_move_accrual_entry/models/res_config_settings.py index 97aa162e3..b05b51e1e 100644 --- a/account_move_accrual_entry/models/res_config_settings.py +++ b/account_move_accrual_entry/models/res_config_settings.py @@ -11,17 +11,16 @@ class ResConfigSettings(models.TransientModel): comodel_name="account.account", related="company_id.accrual_account_id", readonly=False, - domain=[ - ("reconcile", "=", True), - ("deprecated", "=", False), - ("user_type_id.type", "not in", ("receivable", "payable")), - ("is_off_balance", "=", False), - ], + ) + + accrual_journal_id = fields.Many2one( + comodel_name="account.journal", + related="company_id.accrual_journal_id", + readonly=False, ) accrual_account_asset_type_id = fields.Many2one( comodel_name="account.account.type", related="company_id.accrual_account_asset_type_id", readonly=False, - domain=[("internal_group", "=", "asset")], ) diff --git a/account_move_accrual_entry/views/res_config_settings_views.xml b/account_move_accrual_entry/views/res_config_settings_views.xml index 2df6204e3..97cecc24a 100644 --- a/account_move_accrual_entry/views/res_config_settings_views.xml +++ b/account_move_accrual_entry/views/res_config_settings_views.xml @@ -32,6 +32,14 @@ />
+
+