From 42def7f06f4328eeed92f5345a4a25dd2af22b3a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 7 Sep 2021 00:42:41 +0200 Subject: [PATCH 01/34] Add module account_move_name_sequence This module restores the good old behavior where journal entry numbers were generated from a sequence configured on the journal. --- account_move_name_sequence/README.rst | 1 + account_move_name_sequence/__init__.py | 1 + account_move_name_sequence/__manifest__.py | 20 ++++ account_move_name_sequence/models/__init__.py | 2 + .../models/account_journal.py | 96 ++++++++++++++++ .../models/account_move.py | 32 ++++++ .../readme/CONFIGURE.rst | 3 + .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 14 +++ .../security/ir.model.access.csv | 2 + account_move_name_sequence/tests/__init__.py | 1 + .../tests/test_account_move_name_seq.py | 107 ++++++++++++++++++ .../views/account_journal.xml | 34 ++++++ 13 files changed, 314 insertions(+) create mode 100644 account_move_name_sequence/README.rst create mode 100644 account_move_name_sequence/__init__.py create mode 100644 account_move_name_sequence/__manifest__.py create mode 100644 account_move_name_sequence/models/__init__.py create mode 100644 account_move_name_sequence/models/account_journal.py create mode 100644 account_move_name_sequence/models/account_move.py create mode 100644 account_move_name_sequence/readme/CONFIGURE.rst create mode 100644 account_move_name_sequence/readme/CONTRIBUTORS.rst create mode 100644 account_move_name_sequence/readme/DESCRIPTION.rst create mode 100644 account_move_name_sequence/security/ir.model.access.csv create mode 100644 account_move_name_sequence/tests/__init__.py create mode 100644 account_move_name_sequence/tests/test_account_move_name_seq.py create mode 100644 account_move_name_sequence/views/account_journal.xml diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst new file mode 100644 index 00000000..2627cab2 --- /dev/null +++ b/account_move_name_sequence/README.rst @@ -0,0 +1 @@ +Will be auto-generated from the readme subdir diff --git a/account_move_name_sequence/__init__.py b/account_move_name_sequence/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/account_move_name_sequence/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py new file mode 100644 index 00000000..b0b62405 --- /dev/null +++ b/account_move_name_sequence/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Account Move Number Sequence", + "version": "14.0.1.0.0", + "category": "Accounting", + "license": "AGPL-3", + "summary": "Generate journal entry number from sequence", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/account-financial-tools", + "depends": ["account"], + "data": [ + "views/account_journal.xml", + "security/ir.model.access.csv", + ], + "installable": True, +} diff --git a/account_move_name_sequence/models/__init__.py b/account_move_name_sequence/models/__init__.py new file mode 100644 index 00000000..067db8c5 --- /dev/null +++ b/account_move_name_sequence/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_journal +from . import account_move diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py new file mode 100644 index 00000000..2d616d00 --- /dev/null +++ b/account_move_name_sequence/models/account_journal.py @@ -0,0 +1,96 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + sequence_id = fields.Many2one( + "ir.sequence", + string="Entry Sequence", + copy=False, + check_company=True, + domain="[('company_id', '=', company_id)]", + help="This sequence will be used to generate the journal entry number.", + ) + refund_sequence = fields.Boolean( + string="Dedicated Credit Note Sequence", + default=True, + help="If enabled, you will be able to setup a sequence dedicated for refunds.", + ) + refund_sequence_id = fields.Many2one( + "ir.sequence", + string="Credit Note Entry Sequence", + copy=False, + check_company=True, + domain="[('company_id', '=', company_id)]", + help="This sequence will be used to generate the journal entry number for refunds.", + ) + + @api.constrains("refund_sequence_id", "sequence_id") + def _check_journal_sequence(self): + for journal in self: + if ( + journal.refund_sequence_id + and journal.sequence_id + and journal.refund_sequence_id == journal.sequence_id + ): + raise ValidationError( + _( + "On journal '%s', the same sequence is used as " + "Entry Sequence and Credit Note Entry Sequence." + ) + % journal.display_name + ) + if journal.sequence_id and not journal.sequence_id.company_id: + raise ValidationError( + _( + "The company is not set on sequence '%s' configured on " + "journal '%s'." + ) + % (journal.sequence_id.display_name, journal.display_name) + ) + if journal.refund_sequence_id and not journal.refund_sequence_id.company_id: + raise ValidationError( + _( + "The company is not set on sequence '%s' configured as " + "credit note sequence of journal '%s'." + ) + % (journal.refund_sequence_id.display_name, journal.display_name) + ) + + @api.model + def create(self, vals): + if not vals.get("sequence_id"): + vals["sequence_id"] = self._create_sequence(vals).id + if ( + vals.get("type") in ("sale", "purchase") + and vals.get("refund_sequence") + and not vals.get("refund_sequence_id") + ): + vals["refund_sequence_id"] = self._create_sequence(vals, refund=True).id + return super().create(vals) + + @api.model + def _prepare_sequence(self, vals, refund=False): + code = vals.get("code") and vals["code"].upper() or "" + prefix = "%s%s/%%(range_year)s/" % (refund and "R" or "", code) + seq_vals = { + "name": "%s%s" + % (vals.get("name", _("Sequence")), refund and _("Refund") + " " or ""), + "company_id": vals.get("company_id") or self.env.company.id, + "implementation": "no_gap", + "prefix": prefix, + "padding": 4, + "use_date_range": True, + } + return seq_vals + + @api.model + def _create_sequence(self, vals, refund=False): + seq_vals = self._prepare_sequence(vals, refund=refund) + return self.env["ir.sequence"].sudo().create(seq_vals) diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py new file mode 100644 index 00000000..986d64dd --- /dev/null +++ b/account_move_name_sequence/models/account_move.py @@ -0,0 +1,32 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class AccountMove(models.Model): + _inherit = "account.move" + + def _compute_name(self): + for move in self.filtered( + lambda m: (m.name == "/" or not m.name) + and m.state == "posted" + and m.journal_id + and m.journal_id.sequence_id + ): + if ( + move.move_type in ("out_refund", "in_refund") + and move.journal_id.type in ("sale", "purchase") + and move.journal_id.refund_sequence + and move.journal_id.refund_sequence_id + ): + seq = move.journal_id.refund_sequence_id + else: + seq = move.journal_id.sequence_id + move.name = seq.next_by_id(sequence_date=move.date) + super()._compute_name() + for move in self.filtered( + lambda m: m.name and m.name != "/" and m.state != "posted" + ): + move.name = "/" diff --git a/account_move_name_sequence/readme/CONFIGURE.rst b/account_move_name_sequence/readme/CONFIGURE.rst new file mode 100644 index 00000000..1b4bf54b --- /dev/null +++ b/account_move_name_sequence/readme/CONFIGURE.rst @@ -0,0 +1,3 @@ +On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal. + +On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds. diff --git a/account_move_name_sequence/readme/CONTRIBUTORS.rst b/account_move_name_sequence/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..ff65d68c --- /dev/null +++ b/account_move_name_sequence/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/account_move_name_sequence/readme/DESCRIPTION.rst b/account_move_name_sequence/readme/DESCRIPTION.rst new file mode 100644 index 00000000..7ec4dd21 --- /dev/null +++ b/account_move_name_sequence/readme/DESCRIPTION.rst @@ -0,0 +1,14 @@ +In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal. + +In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: + +* the available options for the sequence are limited, +* it is not possible to configure the sequence in advance before the deployment in production, +* as it is error-prone, they added a *Resequence* wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries, +* the `piece of code `_ that handle this is not easy to understand and quite difficult to debug. + +For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. + +The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used. + +The module removes access to the *Resequence* wizard on journal entries. diff --git a/account_move_name_sequence/security/ir.model.access.csv b/account_move_name_sequence/security/ir.model.access.csv new file mode 100644 index 00000000..6247bc1e --- /dev/null +++ b/account_move_name_sequence/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 +account.access_account_resequence,Remove rights on account.resequence.wizard,account.model_account_resequence_wizard,account.group_account_manager,0,0,0,0 diff --git a/account_move_name_sequence/tests/__init__.py b/account_move_name_sequence/tests/__init__.py new file mode 100644 index 00000000..5de02aaf --- /dev/null +++ b/account_move_name_sequence/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_move_name_seq diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py new file mode 100644 index 00000000..1ba0f2ac --- /dev/null +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -0,0 +1,107 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from datetime import datetime + +from odoo import fields +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestAccountMoveNameSequence(TransactionCase): + def setUp(self): + super().setUp() + self.company = self.env.ref("base.main_company") + self.misc_journal = self.env["account.journal"].create( + { + "name": "Test Journal Move name seq", + "code": "ADLM", + "type": "general", + "company_id": self.company.id, + } + ) + self.purchase_journal = self.env["account.journal"].create( + { + "name": "Test Purchase Journal Move name seq", + "code": "ADLP", + "type": "purchase", + "company_id": self.company.id, + "refund_sequence": True, + } + ) + self.accounts = self.env["account.account"].search( + [("company_id", "=", self.company.id)], limit=2 + ) + self.account1 = self.accounts[0] + self.account2 = self.accounts[1] + self.date = datetime.now() + + def test_seq_creation(self): + self.assertTrue(self.misc_journal.sequence_id) + seq = self.misc_journal.sequence_id + self.assertEqual(seq.company_id, self.company) + self.assertEqual(seq.implementation, "no_gap") + self.assertEqual(seq.padding, 4) + self.assertTrue(seq.use_date_range) + self.assertTrue(self.purchase_journal.sequence_id) + self.assertTrue(self.purchase_journal.refund_sequence_id) + seq = self.purchase_journal.refund_sequence_id + self.assertEqual(seq.company_id, self.company) + self.assertEqual(seq.implementation, "no_gap") + self.assertEqual(seq.padding, 4) + self.assertTrue(seq.use_date_range) + + def test_misc_move_name(self): + move = self.env["account.move"].create( + { + "date": self.date, + "journal_id": self.misc_journal.id, + "line_ids": [ + (0, 0, {"account_id": self.account1.id, "debit": 10}), + (0, 0, {"account_id": self.account2.id, "credit": 10}), + ], + } + ) + self.assertEqual(move.name, "/") + move.action_post() + seq = self.misc_journal.sequence_id + move_name = "%s%s" % (seq.prefix, "1".zfill(seq.padding)) + move_name = move_name.replace("%(range_year)s", str(self.date.year)) + self.assertEqual(move.name, move_name) + self.assertTrue(seq.date_range_ids) + drange_count = self.env["ir.sequence.date_range"].search_count( + [ + ("sequence_id", "=", seq.id), + ("date_from", "=", fields.Date.add(self.date, month=1, day=1)), + ] + ) + self.assertEqual(drange_count, 1) + + def test_in_refund(self): + in_refund_invoice = self.env["account.move"].create( + { + "journal_id": self.purchase_journal.id, + "invoice_date": self.date, + "partner_id": self.env.ref("base.res_partner_3").id, + "move_type": "in_refund", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account1.id, + "price_unit": 42.0, + "quantity": 12, + }, + ) + ], + } + ) + self.assertEqual(in_refund_invoice.name, "/") + in_refund_invoice.action_post() + seq = self.purchase_journal.refund_sequence_id + move_name = "%s%s" % (seq.prefix, "1".zfill(seq.padding)) + move_name = move_name.replace("%(range_year)s", str(self.date.year)) + self.assertEqual(in_refund_invoice.name, move_name) diff --git a/account_move_name_sequence/views/account_journal.xml b/account_move_name_sequence/views/account_journal.xml new file mode 100644 index 00000000..8c557014 --- /dev/null +++ b/account_move_name_sequence/views/account_journal.xml @@ -0,0 +1,34 @@ + + + + + + account.journal + + + + + + + + + + + From 4aeaa9ca51ba15e824edcbf307c0384ae0e46ca4 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 8 Sep 2021 14:21:43 +0200 Subject: [PATCH 02/34] sequence is now required on journals Add post-install script to create a sequence for all existing journals Update README accordingly --- account_move_name_sequence/__init__.py | 1 + account_move_name_sequence/__manifest__.py | 2 + .../models/account_journal.py | 1 + .../models/account_move.py | 55 ++++++++++++------- account_move_name_sequence/post_install.py | 25 +++++++++ .../readme/CONFIGURE.rst | 2 + .../tests/test_account_move_name_seq.py | 6 ++ .../views/account_journal.xml | 32 +++++------ .../views/account_move.xml | 33 +++++++++++ 9 files changed, 118 insertions(+), 39 deletions(-) create mode 100644 account_move_name_sequence/post_install.py create mode 100644 account_move_name_sequence/views/account_move.xml diff --git a/account_move_name_sequence/__init__.py b/account_move_name_sequence/__init__.py index 0650744f..f8149cf4 100644 --- a/account_move_name_sequence/__init__.py +++ b/account_move_name_sequence/__init__.py @@ -1 +1,2 @@ +from .post_install import create_journal_sequences from . import models diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index b0b62405..2d131aab 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -14,7 +14,9 @@ "depends": ["account"], "data": [ "views/account_journal.xml", + "views/account_move.xml", "security/ir.model.access.csv", ], + "post_init_hook": "create_journal_sequences", "installable": True, } diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index 2d616d00..a1e20146 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -13,6 +13,7 @@ class AccountJournal(models.Model): "ir.sequence", string="Entry Sequence", copy=False, + required=True, check_company=True, domain="[('company_id', '=', company_id)]", help="This sequence will be used to generate the journal entry number.", diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py index 986d64dd..b090eb52 100644 --- a/account_move_name_sequence/models/account_move.py +++ b/account_move_name_sequence/models/account_move.py @@ -2,31 +2,44 @@ # @author: Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models +from odoo import api, fields, models class AccountMove(models.Model): _inherit = "account.move" - def _compute_name(self): - for move in self.filtered( - lambda m: (m.name == "/" or not m.name) - and m.state == "posted" - and m.journal_id - and m.journal_id.sequence_id - ): + name = fields.Char(compute="_compute_name_by_sequence") + # highest_name, sequence_prefix and sequence_number are not needed any more + # -> compute=False to improve perf + highest_name = fields.Char(compute=False) + sequence_prefix = fields.Char(compute=False) + sequence_number = fields.Integer(compute=False) + + @api.depends("state", "journal_id", "date") + def _compute_name_by_sequence(self): + for move in self: + name = move.name or "/" + # I can't use posted_before in this IF because + # posted_before is set to True in _post() at the same + # time as state is set to "posted" if ( - move.move_type in ("out_refund", "in_refund") - and move.journal_id.type in ("sale", "purchase") - and move.journal_id.refund_sequence - and move.journal_id.refund_sequence_id + move.state == "posted" + and (not move.name or move.name == "/") + and move.journal_id + and move.journal_id.sequence_id ): - seq = move.journal_id.refund_sequence_id - else: - seq = move.journal_id.sequence_id - move.name = seq.next_by_id(sequence_date=move.date) - super()._compute_name() - for move in self.filtered( - lambda m: m.name and m.name != "/" and m.state != "posted" - ): - move.name = "/" + if ( + move.move_type in ("out_refund", "in_refund") + and move.journal_id.type in ("sale", "purchase") + and move.journal_id.refund_sequence + and move.journal_id.refund_sequence_id + ): + seq = move.journal_id.refund_sequence_id + else: + seq = move.journal_id.sequence_id + name = seq.next_by_id(sequence_date=move.date) + move.name = name + + # We must by-pass this constraint of sequence.mixin + def _constrains_date_sequence(self): + return True diff --git a/account_move_name_sequence/post_install.py b/account_move_name_sequence/post_install.py new file mode 100644 index 00000000..5384a8cb --- /dev/null +++ b/account_move_name_sequence/post_install.py @@ -0,0 +1,25 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, api + + +def create_journal_sequences(cr, registry): + with api.Environment.manage(): + env = api.Environment(cr, SUPERUSER_ID, {}) + journals = env["account.journal"].with_context(active_test=False).search([]) + for journal in journals: + vals = {} + journal_vals = { + "code": journal.code, + "name": journal.name, + "company_id": journal.company_id.id, + } + seq_vals = journal._prepare_sequence(journal_vals) + vals["sequence_id"] = env["ir.sequence"].create(seq_vals).id + if journal.type in ("sale", "purchase") and journal.refund_sequence: + rseq_vals = journal._prepare_sequence(journal_vals, refund=True) + vals["refund_sequence_id"] = env["ir.sequence"].create(rseq_vals).id + journal.write(vals) + return diff --git a/account_move_name_sequence/readme/CONFIGURE.rst b/account_move_name_sequence/readme/CONFIGURE.rst index 1b4bf54b..b2998870 100644 --- a/account_move_name_sequence/readme/CONFIGURE.rst +++ b/account_move_name_sequence/readme/CONFIGURE.rst @@ -1,3 +1,5 @@ On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal. On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds. + +Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option *Dedicated Credit Note Sequence* on existing sale and purchase journals if you don't want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry. diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py index 1ba0f2ac..c6acf33c 100644 --- a/account_move_name_sequence/tests/test_account_move_name_seq.py +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -78,6 +78,9 @@ class TestAccountMoveNameSequence(TransactionCase): ] ) self.assertEqual(drange_count, 1) + move.button_draft() + move.action_post() + self.assertEqual(move.name, move_name) def test_in_refund(self): in_refund_invoice = self.env["account.move"].create( @@ -105,3 +108,6 @@ class TestAccountMoveNameSequence(TransactionCase): move_name = "%s%s" % (seq.prefix, "1".zfill(seq.padding)) move_name = move_name.replace("%(range_year)s", str(self.date.year)) self.assertEqual(in_refund_invoice.name, move_name) + in_refund_invoice.button_draft() + in_refund_invoice.action_post() + self.assertEqual(in_refund_invoice.name, move_name) diff --git a/account_move_name_sequence/views/account_journal.xml b/account_move_name_sequence/views/account_journal.xml index 8c557014..073d40be 100644 --- a/account_move_name_sequence/views/account_journal.xml +++ b/account_move_name_sequence/views/account_journal.xml @@ -6,29 +6,25 @@ --> - - account.journal - - - - + account.journal + + + + - - + + - - - + + + - + diff --git a/account_move_name_sequence/views/account_move.xml b/account_move_name_sequence/views/account_move.xml new file mode 100644 index 00000000..cb945731 --- /dev/null +++ b/account_move_name_sequence/views/account_move.xml @@ -0,0 +1,33 @@ + + + + + + account.move + + + + {'invisible': [('name', '=', '/')]} + + + {'readonly': 1} + + + {'invisible': 1} + + + + + From d1d6874aad0b2e71413c16c10e5edf6fd0cb9930 Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Thu, 5 May 2022 15:18:14 +0000 Subject: [PATCH 03/34] [REF] account_move_name_sequence: Add number_next_actual and date range lines data based on current moves --- account_move_name_sequence/__manifest__.py | 4 +- .../models/account_journal.py | 158 +++++++++++++++++- account_move_name_sequence/post_install.py | 7 +- .../readme/CONTRIBUTORS.rst | 1 + .../views/account_journal.xml | 5 +- 5 files changed, 164 insertions(+), 11 deletions(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 2d131aab..1ce93e5f 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -1,5 +1,7 @@ # Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre +# @author: Moisés López # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { @@ -8,7 +10,7 @@ "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", - "author": "Akretion,Odoo Community Association (OCA)", + "author": "Akretion,Vauxoo,Odoo Community Association (OCA)", "maintainers": ["alexis-via"], "website": "https://github.com/OCA/account-financial-tools", "depends": ["account"], diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index a1e20146..740e01e9 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -1,10 +1,18 @@ # Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre +# @author: Moisés López # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from dateutil.relativedelta import relativedelta + from odoo import _, api, fields, models from odoo.exceptions import ValidationError +_logger = logging.getLogger(__name__) + class AccountJournal(models.Model): _inherit = "account.journal" @@ -13,16 +21,10 @@ class AccountJournal(models.Model): "ir.sequence", string="Entry Sequence", copy=False, - required=True, check_company=True, domain="[('company_id', '=', company_id)]", help="This sequence will be used to generate the journal entry number.", ) - refund_sequence = fields.Boolean( - string="Dedicated Credit Note Sequence", - default=True, - help="If enabled, you will be able to setup a sequence dedicated for refunds.", - ) refund_sequence_id = fields.Many2one( "ir.sequence", string="Credit Note Entry Sequence", @@ -31,6 +33,8 @@ class AccountJournal(models.Model): domain="[('company_id', '=', company_id)]", help="This sequence will be used to generate the journal entry number for refunds.", ) + # Redefine the default to True as <=v13.0 + refund_sequence = fields.Boolean(default=True) @api.constrains("refund_sequence_id", "sequence_id") def _check_journal_sequence(self): @@ -95,3 +99,145 @@ class AccountJournal(models.Model): def _create_sequence(self, vals, refund=False): seq_vals = self._prepare_sequence(vals, refund=refund) return self.env["ir.sequence"].sudo().create(seq_vals) + + def _prepare_sequence_current_moves(self, refund=False): + """Get sequence dict values the journal based on current moves""" + self.ensure_one() + move_domain = [ + ("journal_id", "=", self.id), + ("name", "!=", "/"), + ] + if self.refund_sequence: + #  Based on original Odoo behavior + if refund: + move_domain.append(("move_type", "in", ("out_refund", "in_refund"))) + else: + move_domain.append(("move_type", "not in", ("out_refund", "in_refund"))) + last_move = self.env["account.move"].search( + move_domain, limit=1, order="id DESC" + ) + msg_err = ( + "Journal %s could not get sequence %s values based on current moves. " + "Using default values." % (self.id, refund and "refund" or "") + ) + if not last_move: + _logger.warning("%s %s", msg_err, "No moves found") + return {} + try: + with self.env.cr.savepoint(): + # get the current sequence values could be buggy to get + # But even we can use the default values + # or do manual changes instead of raising errors + last_sequence = last_move._get_last_sequence() + if not last_sequence: + last_sequence = ( + last_move._get_last_sequence(relaxed=True) + or last_move._get_starting_sequence() + ) + + __, seq_format_values = last_move._get_sequence_format_param( + last_sequence + ) + prefix1 = seq_format_values["prefix1"] + prefix = prefix1 + if seq_format_values["year_length"] == 4: + prefix += "%(range_year)s" + elif seq_format_values["year_length"] == 2: + prefix += "%(range_y)s" + else: + # If there is not year so current values are valid + seq_vals = { + "padding": seq_format_values["seq_length"], + "suffix": seq_format_values["suffix"], + "prefix": prefix, + "date_range_ids": [], + "use_date_range": False, + "number_next_actual": seq_format_values["seq"] + 1, + } + return seq_vals + prefix2 = seq_format_values.get("prefix2") or "" + prefix += prefix2 + month = seq_format_values.get("month") # It is 0 if only have year + if month: + prefix += "%(range_month)s" + prefix3 = seq_format_values.get("prefix3") or "" + where_name_value = "%s%s%s%s%s%%" % ( + prefix1, + "_" * seq_format_values["year_length"], + prefix2, + "_" * bool(month) * 2, + prefix3, + ) + prefixes = prefix1 + prefix2 + select_year = ( + "split_part(name, '%s', %d)" % (prefix2, prefixes.count(prefix2)) + if prefix2 + else "''" + ) + prefixes += prefix3 + select_month = ( + "split_part(name, '%s', %d)" % (prefix3, prefixes.count(prefix3)) + if prefix3 + else "''" + ) + select_max_number = ( + "MAX(split_part(name, '%s', %d)::INTEGER) AS max_number" + % (prefixes[-1], prefixes.count(prefixes[-1]) + 1) + ) + query = ( + "SELECT %s, %s, %s FROM account_move " + "WHERE name LIKE %%s AND journal_id=%%s GROUP BY 1,2" + ) % ( + select_year, + select_month, + select_max_number, + ) + # It is not using user input + # pylint: disable=sql-injection + self.env.cr.execute(query, (where_name_value, self.id)) + res = self.env.cr.fetchall() + prefix += prefix3 + seq_vals = { + "padding": seq_format_values["seq_length"], + "suffix": seq_format_values["suffix"], + "prefix": prefix, + "date_range_ids": [], + "use_date_range": True, + } + for year, month, max_number in res: + if not year and not month: + seq_vals.update( + { + "use_date_range": False, + "number_next_actual": max_number + 1, + } + ) + continue + if len(year) == 2: + # Year >=50 will be considered as last century 1950 + # Year <=49 will be considered as current century 2049 + if int(year) >= 50: + year = "19" + year + else: + year = "20" + year + if month: + date_from = fields.Date.to_date("%s-%s-1" % (year, month)) + date_to = date_from + relativedelta(day=31) + else: + date_from = fields.Date.to_date("%s-1-1" % year) + date_to = fields.Date.to_date("%s-12-31" % year) + seq_vals["date_range_ids"].append( + ( + 0, + 0, + { + "date_from": date_from, + "date_to": date_to, + "number_next_actual": max_number + 1, + }, + ) + ) + return seq_vals + except Exception as e: + _logger.warning("%s %s", msg_err, e) + return {} diff --git a/account_move_name_sequence/post_install.py b/account_move_name_sequence/post_install.py index 5384a8cb..b4f8b997 100644 --- a/account_move_name_sequence/post_install.py +++ b/account_move_name_sequence/post_install.py @@ -1,5 +1,7 @@ # Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre +# @author: Moisés López # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import SUPERUSER_ID, api @@ -10,16 +12,17 @@ def create_journal_sequences(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) journals = env["account.journal"].with_context(active_test=False).search([]) for journal in journals: - vals = {} journal_vals = { "code": journal.code, "name": journal.name, "company_id": journal.company_id.id, } seq_vals = journal._prepare_sequence(journal_vals) - vals["sequence_id"] = env["ir.sequence"].create(seq_vals).id + seq_vals.update(journal._prepare_sequence_current_moves()) + vals = {"sequence_id": env["ir.sequence"].create(seq_vals).id} if journal.type in ("sale", "purchase") and journal.refund_sequence: rseq_vals = journal._prepare_sequence(journal_vals, refund=True) + rseq_vals.update(journal._prepare_sequence_current_moves(refund=True)) vals["refund_sequence_id"] = env["ir.sequence"].create(rseq_vals).id journal.write(vals) return diff --git a/account_move_name_sequence/readme/CONTRIBUTORS.rst b/account_move_name_sequence/readme/CONTRIBUTORS.rst index ff65d68c..c3f90701 100644 --- a/account_move_name_sequence/readme/CONTRIBUTORS.rst +++ b/account_move_name_sequence/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Alexis de Lattre +* Moisés López diff --git a/account_move_name_sequence/views/account_journal.xml b/account_move_name_sequence/views/account_journal.xml index 073d40be..6cc643a7 100644 --- a/account_move_name_sequence/views/account_journal.xml +++ b/account_move_name_sequence/views/account_journal.xml @@ -14,14 +14,15 @@ From 87f2818191168278791dab5dfa59bf91e2de3458 Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Tue, 10 May 2022 20:10:29 +0000 Subject: [PATCH 04/34] [FIX] ir_sequence: Fix creating date_range_seq with range_month and range_day More info about: - https://github.com/odoo/odoo/pull/91019 TODO: Revert this commit after it is merged --- account_move_name_sequence/models/__init__.py | 1 + .../models/ir_sequence.py | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 account_move_name_sequence/models/ir_sequence.py diff --git a/account_move_name_sequence/models/__init__.py b/account_move_name_sequence/models/__init__.py index 067db8c5..069c9b59 100644 --- a/account_move_name_sequence/models/__init__.py +++ b/account_move_name_sequence/models/__init__.py @@ -1,2 +1,3 @@ from . import account_journal from . import account_move +from . import ir_sequence diff --git a/account_move_name_sequence/models/ir_sequence.py b/account_move_name_sequence/models/ir_sequence.py new file mode 100644 index 00000000..c7ee985f --- /dev/null +++ b/account_move_name_sequence/models/ir_sequence.py @@ -0,0 +1,58 @@ +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class IrSequence(models.Model): + _inherit = "ir.sequence" + + def _create_date_range_seq(self, date): + # Fix issue creating new date range for future dates + # It assigns more than one month + # TODO: Remove if odoo merge the following PR: + # https://github.com/odoo/odoo/pull/91019 + date_obj = fields.Date.from_string(date) + prefix_suffix = "%s %s" % (self.prefix, self.suffix) + if "%(range_day)s" in prefix_suffix: + date_from = date_obj + date_to = date_obj + elif "%(range_month)s" in prefix_suffix: + date_from = date_obj + relativedelta(day=1) + date_to = date_obj + relativedelta(day=31) + else: + date_from = date_obj + relativedelta(day=1, month=1) + date_to = date_obj + relativedelta(day=31, month=12) + date_range = self.env["ir.sequence.date_range"].search( + [ + ("sequence_id", "=", self.id), + ("date_from", ">=", date), + ("date_from", "<=", date_to), + ], + order="date_from desc", + limit=1, + ) + if date_range: + date_to = date_range.date_from + relativedelta(days=-1) + date_range = self.env["ir.sequence.date_range"].search( + [ + ("sequence_id", "=", self.id), + ("date_to", ">=", date_from), + ("date_to", "<=", date), + ], + order="date_to desc", + limit=1, + ) + if date_range: + date_from = date_range.date_to + relativedelta(days=1) + seq_date_range = ( + self.env["ir.sequence.date_range"] + .sudo() + .create( + { + "date_from": date_from, + "date_to": date_to, + "sequence_id": self.id, + } + ) + ) + return seq_date_range From 52cbe647be1a1ef1881e693bc1a1932a0550ac13 Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Wed, 11 May 2022 17:18:36 +0000 Subject: [PATCH 05/34] [REF] account_move_name_sequence: Discard journals already configured --- account_move_name_sequence/post_install.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/account_move_name_sequence/post_install.py b/account_move_name_sequence/post_install.py index b4f8b997..807e4aa6 100644 --- a/account_move_name_sequence/post_install.py +++ b/account_move_name_sequence/post_install.py @@ -10,7 +10,11 @@ from odoo import SUPERUSER_ID, api def create_journal_sequences(cr, registry): with api.Environment.manage(): env = api.Environment(cr, SUPERUSER_ID, {}) - journals = env["account.journal"].with_context(active_test=False).search([]) + journals = ( + env["account.journal"] + .with_context(active_test=False) + .search([("sequence_id", "!=", False)]) + ) for journal in journals: journal_vals = { "code": journal.code, From 9ac1af9106f4ed1f688b78810dab5a8f569714ad Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 12 May 2022 17:00:22 +0000 Subject: [PATCH 06/34] [UPD] Update account_move_name_sequence.pot --- .../i18n/account_move_name_sequence.pot | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 account_move_name_sequence/i18n/account_move_name_sequence.pot diff --git a/account_move_name_sequence/i18n/account_move_name_sequence.pot b/account_move_name_sequence/i18n/account_move_name_sequence.pot new file mode 100644 index 00000000..fdc84102 --- /dev/null +++ b/account_move_name_sequence/i18n/account_move_name_sequence.pot @@ -0,0 +1,141 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_move_name_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_move_name_sequence +#: model:ir.model.fields,help:account_move_name_sequence.field_account_journal__refund_sequence +msgid "" +"Check this box if you don't want to share the same sequence for invoices and" +" credit notes made from this journal" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__refund_sequence_id +msgid "Credit Note Entry Sequence" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__refund_sequence +msgid "Dedicated Credit Note Sequence" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__display_name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__display_name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence__display_name +msgid "Display Name" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__sequence_id +msgid "Entry Sequence" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_bank_statement_line__highest_name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__highest_name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_payment__highest_name +msgid "Highest Name" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__id +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__id +#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence__id +msgid "ID" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model,name:account_move_name_sequence.model_account_journal +msgid "Journal" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model,name:account_move_name_sequence.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal____last_update +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move____last_update +#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence____last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_bank_statement_line__name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__name +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_payment__name +msgid "Number" +msgstr "" + +#. module: account_move_name_sequence +#: code:addons/account_move_name_sequence/models/account_journal.py:0 +#, python-format +msgid "" +"On journal '%s', the same sequence is used as Entry Sequence and Credit Note" +" Entry Sequence." +msgstr "" + +#. module: account_move_name_sequence +#: code:addons/account_move_name_sequence/models/account_journal.py:0 +#, python-format +msgid "Refund" +msgstr "" + +#. module: account_move_name_sequence +#: code:addons/account_move_name_sequence/models/account_journal.py:0 +#: model:ir.model,name:account_move_name_sequence.model_ir_sequence +#, python-format +msgid "Sequence" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_bank_statement_line__sequence_number +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__sequence_number +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_payment__sequence_number +msgid "Sequence Number" +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_bank_statement_line__sequence_prefix +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__sequence_prefix +#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_payment__sequence_prefix +msgid "Sequence Prefix" +msgstr "" + +#. module: account_move_name_sequence +#: code:addons/account_move_name_sequence/models/account_journal.py:0 +#, python-format +msgid "" +"The company is not set on sequence '%s' configured as credit note sequence " +"of journal '%s'." +msgstr "" + +#. module: account_move_name_sequence +#: code:addons/account_move_name_sequence/models/account_journal.py:0 +#, python-format +msgid "The company is not set on sequence '%s' configured on journal '%s'." +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,help:account_move_name_sequence.field_account_journal__refund_sequence_id +msgid "" +"This sequence will be used to generate the journal entry number for refunds." +msgstr "" + +#. module: account_move_name_sequence +#: model:ir.model.fields,help:account_move_name_sequence.field_account_journal__sequence_id +msgid "This sequence will be used to generate the journal entry number." +msgstr "" From 7e0350aad050b956de5cea8ee8fcb260a76f0674 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 12 May 2022 17:05:15 +0000 Subject: [PATCH 07/34] [UPD] README.rst --- account_move_name_sequence/README.rst | 106 ++++- .../static/description/index.html | 440 ++++++++++++++++++ 2 files changed, 545 insertions(+), 1 deletion(-) create mode 100644 account_move_name_sequence/static/description/index.html diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst index 2627cab2..fe18caeb 100644 --- a/account_move_name_sequence/README.rst +++ b/account_move_name_sequence/README.rst @@ -1 +1,105 @@ -Will be auto-generated from the readme subdir +============================ +Account Move Number Sequence +============================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github + :target: https://github.com/OCA/account-financial-tools/tree/14.0/account_move_name_sequence + :alt: OCA/account-financial-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-financial-tools-14-0/account-financial-tools-14-0-account_move_name_sequence + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/92/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal. + +In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: + +* the available options for the sequence are limited, +* it is not possible to configure the sequence in advance before the deployment in production, +* as it is error-prone, they added a *Resequence* wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries, +* the `piece of code `_ that handle this is not easy to understand and quite difficult to debug. + +For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. + +The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used. + +The module removes access to the *Resequence* wizard on journal entries. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal. + +On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds. + +Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option *Dedicated Credit Note Sequence* on existing sale and purchase journals if you don't want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion +* Vauxoo + +Contributors +~~~~~~~~~~~~ + +* Alexis de Lattre +* Moisés López + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-alexis-via| image:: https://github.com/alexis-via.png?size=40px + :target: https://github.com/alexis-via + :alt: alexis-via + +Current `maintainer `__: + +|maintainer-alexis-via| + +This module is part of the `OCA/account-financial-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_move_name_sequence/static/description/index.html b/account_move_name_sequence/static/description/index.html new file mode 100644 index 00000000..5b60fcff --- /dev/null +++ b/account_move_name_sequence/static/description/index.html @@ -0,0 +1,440 @@ + + + + + + +Account Move Number Sequence + + + +
+

Account Move Number Sequence

+ + +

Beta License: AGPL-3 OCA/account-financial-tools Translate me on Weblate Try me on Runbot

+

In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal.

+

In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks:

+
    +
  • the available options for the sequence are limited,
  • +
  • it is not possible to configure the sequence in advance before the deployment in production,
  • +
  • as it is error-prone, they added a Resequence wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries,
  • +
  • the piece of code that handle this is not easy to understand and quite difficult to debug.
  • +
+

For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare.

+

The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used.

+

The module removes access to the Resequence wizard on journal entries.

+

Table of contents

+ +
+

Configuration

+

On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal.

+

On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds.

+

Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option Dedicated Credit Note Sequence on existing sale and purchase journals if you don’t want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry.

+
+
+

Bug Tracker

+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
  • Vauxoo
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

alexis-via

+

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

+

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

+
+
+
+ + From d45cda0ecb674733785e6419fefae52c7f017c31 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 12 May 2022 17:05:16 +0000 Subject: [PATCH 08/34] [ADD] icon.png --- .../static/description/icon.png | Bin 0 -> 9455 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 account_move_name_sequence/static/description/icon.png diff --git a/account_move_name_sequence/static/description/icon.png b/account_move_name_sequence/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From 1a2b072c4e2d8dbd109c832208515c84d58e2497 Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Fri, 13 May 2022 15:34:58 +0000 Subject: [PATCH 09/34] [FIX] account_move_name_sequence: Fix sequence domain to assign only if it is empty --- account_move_name_sequence/post_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/post_install.py b/account_move_name_sequence/post_install.py index 807e4aa6..ef52eeeb 100644 --- a/account_move_name_sequence/post_install.py +++ b/account_move_name_sequence/post_install.py @@ -13,7 +13,7 @@ def create_journal_sequences(cr, registry): journals = ( env["account.journal"] .with_context(active_test=False) - .search([("sequence_id", "!=", False)]) + .search([("sequence_id", "=", False)]) ) for journal in journals: journal_vals = { From 5add0a43bdac6d2ec450255545e92051331d240c Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 13 May 2022 15:59:23 +0000 Subject: [PATCH 10/34] account_move_name_sequence 14.0.1.0.1 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 1ce93e5f..ff92d0b5 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.0.0", + "version": "14.0.1.0.1", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From 85cb94dc61e166e0e5a8a0a907dd00b0450006bc Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Fri, 13 May 2022 16:14:51 +0000 Subject: [PATCH 11/34] [REF] account_move_name_sequence: Moves with name '/' can not be posted After remove required=True for journal.sequence_id field it is possible to post an invoice with misconfigured journal with empty sequence So, this constraint will raise an error for this kind of cases since that using '/' could raise the unique constraint for all other moves --- account_move_name_sequence/models/account_move.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py index b090eb52..ff1dbc75 100644 --- a/account_move_name_sequence/models/account_move.py +++ b/account_move_name_sequence/models/account_move.py @@ -15,6 +15,15 @@ class AccountMove(models.Model): sequence_prefix = fields.Char(compute=False) sequence_number = fields.Integer(compute=False) + _sql_constraints = [ + ( + "name_state_diagonal", + "CHECK(COALESCE(name, '') NOT IN ('/', '') OR state!='posted')", + 'A move can not be posted with name "/" or empty value\n' + "Check the journal sequence, please", + ), + ] + @api.depends("state", "journal_id", "date") def _compute_name_by_sequence(self): for move in self: From 6caddd3b6ce33b55f1e17a4ac5f9dc13758830f0 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 13 May 2022 17:06:25 +0000 Subject: [PATCH 12/34] [UPD] Update account_move_name_sequence.pot --- .../i18n/account_move_name_sequence.pot | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/account_move_name_sequence/i18n/account_move_name_sequence.pot b/account_move_name_sequence/i18n/account_move_name_sequence.pot index fdc84102..395f8e18 100644 --- a/account_move_name_sequence/i18n/account_move_name_sequence.pot +++ b/account_move_name_sequence/i18n/account_move_name_sequence.pot @@ -13,6 +13,13 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: account_move_name_sequence +#: model:ir.model.constraint,message:account_move_name_sequence.constraint_account_move_name_state_diagonal +msgid "" +"A move can not be posted with name \"/\" or empty value\n" +"Check the journal sequence, please" +msgstr "" + #. module: account_move_name_sequence #: model:ir.model.fields,help:account_move_name_sequence.field_account_journal__refund_sequence msgid "" From caf256db9684ed8e52554335b4edd6869fa00ece Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 13 May 2022 17:12:07 +0000 Subject: [PATCH 13/34] account_move_name_sequence 14.0.1.1.0 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index ff92d0b5..3a836fbd 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.0.1", + "version": "14.0.1.1.0", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From 476532f8716b75e9f40fc0f459ff8a6160325509 Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Fri, 13 May 2022 17:14:30 +0000 Subject: [PATCH 14/34] [FIX] account_move_name_sequence: Fix required journal fields in view The required flag was wrong for sequence_id and refund_sequence_id So, it was not possible to store any change in journal for journal different to sale and purchase --- account_move_name_sequence/views/account_journal.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/account_move_name_sequence/views/account_journal.xml b/account_move_name_sequence/views/account_journal.xml index 6cc643a7..d274975a 100644 --- a/account_move_name_sequence/views/account_journal.xml +++ b/account_move_name_sequence/views/account_journal.xml @@ -13,15 +13,15 @@ From d9df97e89d242700c650049d34af35695309da6f Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 13 May 2022 17:42:49 +0000 Subject: [PATCH 15/34] account_move_name_sequence 14.0.1.2.0 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 3a836fbd..a4960cd8 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.1.0", + "version": "14.0.1.2.0", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From 3cd3182734f00f1ef4e3cc1c7514e1641ee720ca Mon Sep 17 00:00:00 2001 From: Moises Lopez Date: Fri, 13 May 2022 17:46:35 +0000 Subject: [PATCH 16/34] [REF] account_move_name_sequence: Add maintainers to myself --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index a4960cd8..46f9835b 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -11,7 +11,7 @@ "license": "AGPL-3", "summary": "Generate journal entry number from sequence", "author": "Akretion,Vauxoo,Odoo Community Association (OCA)", - "maintainers": ["alexis-via"], + "maintainers": ["alexis-via", "moylop260"], "website": "https://github.com/OCA/account-financial-tools", "depends": ["account"], "data": [ From 3a698a9d246f29589423be3e237d0dc9a095e561 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 13 May 2022 17:52:55 +0000 Subject: [PATCH 17/34] [UPD] README.rst --- account_move_name_sequence/README.rst | 7 +++++-- account_move_name_sequence/static/description/index.html | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst index fe18caeb..7a704a40 100644 --- a/account_move_name_sequence/README.rst +++ b/account_move_name_sequence/README.rst @@ -95,10 +95,13 @@ promote its widespread use. .. |maintainer-alexis-via| image:: https://github.com/alexis-via.png?size=40px :target: https://github.com/alexis-via :alt: alexis-via +.. |maintainer-moylop260| image:: https://github.com/moylop260.png?size=40px + :target: https://github.com/moylop260 + :alt: moylop260 -Current `maintainer `__: +Current `maintainers `__: -|maintainer-alexis-via| +|maintainer-alexis-via| |maintainer-moylop260| This module is part of the `OCA/account-financial-tools `_ project on GitHub. diff --git a/account_move_name_sequence/static/description/index.html b/account_move_name_sequence/static/description/index.html index 5b60fcff..adccba01 100644 --- a/account_move_name_sequence/static/description/index.html +++ b/account_move_name_sequence/static/description/index.html @@ -429,8 +429,8 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

Current maintainer:

-

alexis-via

+

Current maintainers:

+

alexis-via moylop260

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

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

From f90d1bffb4ec089586702ceaf14955c4c24a092a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20L=C3=B3pez?= Date: Thu, 19 May 2022 16:05:34 -0500 Subject: [PATCH 18/34] [REF] account_move_name_sequence: Adding concurrency cases in README --- .../readme/DESCRIPTION.rst | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/account_move_name_sequence/readme/DESCRIPTION.rst b/account_move_name_sequence/readme/DESCRIPTION.rst index 7ec4dd21..9bbf7306 100644 --- a/account_move_name_sequence/readme/DESCRIPTION.rst +++ b/account_move_name_sequence/readme/DESCRIPTION.rst @@ -1,13 +1,61 @@ In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal. -In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: +In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for the next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: * the available options for the sequence are limited, * it is not possible to configure the sequence in advance before the deployment in production, * as it is error-prone, they added a *Resequence* wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries, -* the `piece of code `_ that handle this is not easy to understand and quite difficult to debug. +* the `piece of code `_ that handles this is not easy to understand and quite difficult to debug. -For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. +Odoo>=v14.0 raises new concurrency issues since it locks the last journal entry of the journal to get the new number causing a bottleneck +Even if you only are creating a draft journal entry it locks the last one +It applies to all accounting Journal Entries + +e.g. + + - Customer Invoices + - Credit Notes + - Customer Payments + - Vendor Bills + - Vendor Refunds + - Vendor Payment + - Manual Journal Entries + +Then, the following concurrency errors are being raised now frequently: + +* Editing the last record used to get the new number from another process +* Creating a new draft invoice/payment (not only when posting it) +* Creating a transaction to create an invoice then payment or vice versa raises a deadlock error +* Reconciling the last record it could be a heavy process +* Creating 2 or more Invoices/Bills at the same time +* Creating 2 or more Payments at the same time (Even if your country allows to relax gaps in these kinds of documents, you are not able anymore to change the implementation to standard) +* Creating 2 or more Journal Entries at the same time + + +All these increases in concurrency errors bring more issues since that Odoo is not prepared: + +* Using e-commerce, configured with Invoicing Policy Ordered and Automatic Invoice, the portal users will see errors in the checkout even if the payment was done, the sale order could be in state draft and request a new payment, so double charges +* Using `subscription_template.payment_mode=success_payment` you will see subscriptions with tag "payment exception" +* Using accounting creating invoice or payment, you will see errors then you will need to start the process again and again until you get the lock before another user +* The workers could be used for more time than before since that it could be waiting for release so less concurrent users supported or loading page is shown more frequently affecting the performance + +The new accounting number is a significant bottleneck + +.. image:: https://media.istockphoto.com/vectors/road-highways-with-many-different-vehicles-vector-id1328678690 + + +If you do not believe all these issues are occurring, we have created the following issues and unittest to reproduce errors in v14.0 including the deadlock, but not v13.0: + + - Passing unittest for `13.0 - [REF] account: Adding unittests for concurrency issues in account_move sequences `_ + - Concurrency errors for `14.0 - [REF] account: Adding unittests for concurrency issues in account_move sequences `_ + - `Stress testing and issue reported to Odoo `_ + - `[BUG] account: Concurrency errors increased considerably in account.move for Odoo>=v14.0 #91873 `_ + + +Using this module, you can configure what kind of documents the gap sequence may be relaxed +And even if you must use no-gap in your company or country it will reduce the concurrency issues since the module is using an extra table (ir_sequence) instead of locking the last record + +For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who considers that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used. From 4a0c64df4c6b563accf4c98009b5a6fec455dc3d Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 20 May 2022 14:55:28 +0000 Subject: [PATCH 19/34] [UPD] README.rst --- account_move_name_sequence/README.rst | 54 ++++++++++++- .../static/description/index.html | 75 +++++++++++++++---- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst index 7a704a40..07ddb325 100644 --- a/account_move_name_sequence/README.rst +++ b/account_move_name_sequence/README.rst @@ -27,14 +27,62 @@ Account Move Number Sequence In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal. -In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: +In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for the next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks: * the available options for the sequence are limited, * it is not possible to configure the sequence in advance before the deployment in production, * as it is error-prone, they added a *Resequence* wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries, -* the `piece of code `_ that handle this is not easy to understand and quite difficult to debug. +* the `piece of code `_ that handles this is not easy to understand and quite difficult to debug. -For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. +Odoo>=v14.0 raises new concurrency issues since it locks the last journal entry of the journal to get the new number causing a bottleneck +Even if you only are creating a draft journal entry it locks the last one +It applies to all accounting Journal Entries + +e.g. + + - Customer Invoices + - Credit Notes + - Customer Payments + - Vendor Bills + - Vendor Refunds + - Vendor Payment + - Manual Journal Entries + +Then, the following concurrency errors are being raised now frequently: + +* Editing the last record used to get the new number from another process +* Creating a new draft invoice/payment (not only when posting it) +* Creating a transaction to create an invoice then payment or vice versa raises a deadlock error +* Reconciling the last record it could be a heavy process +* Creating 2 or more Invoices/Bills at the same time +* Creating 2 or more Payments at the same time (Even if your country allows to relax gaps in these kinds of documents, you are not able anymore to change the implementation to standard) +* Creating 2 or more Journal Entries at the same time + + +All these increases in concurrency errors bring more issues since that Odoo is not prepared: + +* Using e-commerce, configured with Invoicing Policy Ordered and Automatic Invoice, the portal users will see errors in the checkout even if the payment was done, the sale order could be in state draft and request a new payment, so double charges +* Using `subscription_template.payment_mode=success_payment` you will see subscriptions with tag "payment exception" +* Using accounting creating invoice or payment, you will see errors then you will need to start the process again and again until you get the lock before another user +* The workers could be used for more time than before since that it could be waiting for release so less concurrent users supported or loading page is shown more frequently affecting the performance + +The new accounting number is a significant bottleneck + +.. image:: https://media.istockphoto.com/vectors/road-highways-with-many-different-vehicles-vector-id1328678690 + + +If you do not believe all these issues are occurring, we have created the following issues and unittest to reproduce errors in v14.0 including the deadlock, but not v13.0: + + - Passing unittest for `13.0 - [REF] account: Adding unittests for concurrency issues in account_move sequences `_ + - Concurrency errors for `14.0 - [REF] account: Adding unittests for concurrency issues in account_move sequences `_ + - `Stress testing and issue reported to Odoo `_ + - `[BUG] account: Concurrency errors increased considerably in account.move for Odoo>=v14.0 #91873 `_ + + +Using this module, you can configure what kind of documents the gap sequence may be relaxed +And even if you must use no-gap in your company or country it will reduce the concurrency issues since the module is using an extra table (ir_sequence) instead of locking the last record + +For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who considers that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare. The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used. diff --git a/account_move_name_sequence/static/description/index.html b/account_move_name_sequence/static/description/index.html index adccba01..1f7fcb01 100644 --- a/account_move_name_sequence/static/description/index.html +++ b/account_move_name_sequence/static/description/index.html @@ -369,37 +369,82 @@ ul.auto-toc { !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/account-financial-tools Translate me on Weblate Try me on Runbot

In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal.

-

In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks:

+

In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for the next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks:

  • the available options for the sequence are limited,
  • it is not possible to configure the sequence in advance before the deployment in production,
  • as it is error-prone, they added a Resequence wizard to re-generate the journal entry numbers, which can be considered as illegal in many countries,
  • -
  • the piece of code that handle this is not easy to understand and quite difficult to debug.
  • +
  • the piece of code that handles this is not easy to understand and quite difficult to debug.
-

For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who consider that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare.

+

Odoo>=v14.0 raises new concurrency issues since it locks the last journal entry of the journal to get the new number causing a bottleneck +Even if you only are creating a draft journal entry it locks the last one +It applies to all accounting Journal Entries

+

e.g.

+
+
    +
  • Customer Invoices
  • +
  • Credit Notes
  • +
  • Customer Payments
  • +
  • Vendor Bills
  • +
  • Vendor Refunds
  • +
  • Vendor Payment
  • +
  • Manual Journal Entries
  • +
+
+

Then, the following concurrency errors are being raised now frequently:

+
    +
  • Editing the last record used to get the new number from another process
  • +
  • Creating a new draft invoice/payment (not only when posting it)
  • +
  • Creating a transaction to create an invoice then payment or vice versa raises a deadlock error
  • +
  • Reconciling the last record it could be a heavy process
  • +
  • Creating 2 or more Invoices/Bills at the same time
  • +
  • Creating 2 or more Payments at the same time (Even if your country allows to relax gaps in these kinds of documents, you are not able anymore to change the implementation to standard)
  • +
  • Creating 2 or more Journal Entries at the same time
  • +
+

All these increases in concurrency errors bring more issues since that Odoo is not prepared:

+
    +
  • Using e-commerce, configured with Invoicing Policy Ordered and Automatic Invoice, the portal users will see errors in the checkout even if the payment was done, the sale order could be in state draft and request a new payment, so double charges
  • +
  • Using subscription_template.payment_mode=success_payment you will see subscriptions with tag “payment exception”
  • +
  • Using accounting creating invoice or payment, you will see errors then you will need to start the process again and again until you get the lock before another user
  • +
  • The workers could be used for more time than before since that it could be waiting for release so less concurrent users supported or loading page is shown more frequently affecting the performance
  • +
+

The new accounting number is a significant bottleneck

+https://media.istockphoto.com/vectors/road-highways-with-many-different-vehicles-vector-id1328678690 +

If you do not believe all these issues are occurring, we have created the following issues and unittest to reproduce errors in v14.0 including the deadlock, but not v13.0:

+
+ +
+

Using this module, you can configure what kind of documents the gap sequence may be relaxed +And even if you must use no-gap in your company or country it will reduce the concurrency issues since the module is using an extra table (ir_sequence) instead of locking the last record

+

For those like me who think that the implementation before Odoo v14.0 was much better, for the accountants who think it should not be possible to manually enter the sequence of a customer invoice, for the auditor who considers that resequencing journal entries is prohibited by law, this module may be a solution to get out of the nightmare.

The field names used in this module to configure the sequence on the journal are exactly the same as in Odoo version 13.0 and previous versions. That way, if you migrate to Odoo version 14.0 and you install this module immediately after the migration, you should keep the previous behavior and the same sequences will continue to be used.

The module removes access to the Resequence wizard on journal entries.

Table of contents

-

Configuration

+

Configuration

On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal.

On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds.

Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option Dedicated Credit Note Sequence on existing sale and purchase journals if you don’t want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry.

-

Bug Tracker

+

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 @@ -407,23 +452,23 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Akretion
  • Vauxoo
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose From cdc7934b6d5d92c36c1c7938e8ec50abda918f03 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 20 May 2022 14:55:28 +0000 Subject: [PATCH 20/34] account_move_name_sequence 14.0.1.2.1 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 46f9835b..1f2f54aa 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.2.0", + "version": "14.0.1.2.1", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From 1653cc46c2a8023076a6eea4fa9136ef93999336 Mon Sep 17 00:00:00 2001 From: Francisco Javier Luna Vazquez Date: Thu, 26 May 2022 09:26:12 -0500 Subject: [PATCH 21/34] [REF] account_move_name_sequence: Use Odoo native methods + Typos --- account_move_name_sequence/__manifest__.py | 7 ++-- .../models/account_journal.py | 4 +-- .../models/ir_sequence.py | 36 ++++++++----------- .../readme/CONFIGURE.rst | 2 +- .../readme/CONTRIBUTORS.rst | 1 + .../views/account_journal.xml | 2 ++ .../views/account_move.xml | 18 +++++----- 7 files changed, 33 insertions(+), 37 deletions(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 1f2f54aa..1859ae30 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -2,6 +2,7 @@ # Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre # @author: Moisés López +# @author: Francisco Luna # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { @@ -11,9 +12,11 @@ "license": "AGPL-3", "summary": "Generate journal entry number from sequence", "author": "Akretion,Vauxoo,Odoo Community Association (OCA)", - "maintainers": ["alexis-via", "moylop260"], + "maintainers": ["alexis-via", "moylop260", "frahikLV"], "website": "https://github.com/OCA/account-financial-tools", - "depends": ["account"], + "depends": [ + "account", + ], "data": [ "views/account_journal.xml", "views/account_move.xml", diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index 740e01e9..41755ee1 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -6,8 +6,6 @@ import logging -from dateutil.relativedelta import relativedelta - from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -222,7 +220,7 @@ class AccountJournal(models.Model): year = "20" + year if month: date_from = fields.Date.to_date("%s-%s-1" % (year, month)) - date_to = date_from + relativedelta(day=31) + date_to = fields.Date.end_of(date_from, "month") else: date_from = fields.Date.to_date("%s-1-1" % year) date_to = fields.Date.to_date("%s-12-31" % year) diff --git a/account_move_name_sequence/models/ir_sequence.py b/account_move_name_sequence/models/ir_sequence.py index c7ee985f..7dc7d265 100644 --- a/account_move_name_sequence/models/ir_sequence.py +++ b/account_move_name_sequence/models/ir_sequence.py @@ -1,5 +1,3 @@ -from dateutil.relativedelta import relativedelta - from odoo import fields, models @@ -12,17 +10,18 @@ class IrSequence(models.Model): # TODO: Remove if odoo merge the following PR: # https://github.com/odoo/odoo/pull/91019 date_obj = fields.Date.from_string(date) + sequence_range = self.env["ir.sequence.date_range"] prefix_suffix = "%s %s" % (self.prefix, self.suffix) if "%(range_day)s" in prefix_suffix: date_from = date_obj date_to = date_obj elif "%(range_month)s" in prefix_suffix: - date_from = date_obj + relativedelta(day=1) - date_to = date_obj + relativedelta(day=31) + date_from = fields.Date.start_of(date_obj, "month") + date_to = fields.Date.end_of(date_obj, "month") else: - date_from = date_obj + relativedelta(day=1, month=1) - date_to = date_obj + relativedelta(day=31, month=12) - date_range = self.env["ir.sequence.date_range"].search( + date_from = fields.Date.start_of(date_obj, "year") + date_to = fields.Date.end_of(date_obj, "year") + date_range = sequence_range.search( [ ("sequence_id", "=", self.id), ("date_from", ">=", date), @@ -32,8 +31,8 @@ class IrSequence(models.Model): limit=1, ) if date_range: - date_to = date_range.date_from + relativedelta(days=-1) - date_range = self.env["ir.sequence.date_range"].search( + date_to = fields.Date.subtract(date_range.date_from, days=1) + date_range = sequence_range.search( [ ("sequence_id", "=", self.id), ("date_to", ">=", date_from), @@ -43,16 +42,11 @@ class IrSequence(models.Model): limit=1, ) if date_range: - date_from = date_range.date_to + relativedelta(days=1) - seq_date_range = ( - self.env["ir.sequence.date_range"] - .sudo() - .create( - { - "date_from": date_from, - "date_to": date_to, - "sequence_id": self.id, - } - ) - ) + date_to = fields.Date.add(date_range.date_to, days=1) + sequence_range_vals = { + "date_from": date_from, + "date_to": date_to, + "sequence_id": self.id, + } + seq_date_range = sequence_range.sudo().create(sequence_range_vals) return seq_date_range diff --git a/account_move_name_sequence/readme/CONFIGURE.rst b/account_move_name_sequence/readme/CONFIGURE.rst index b2998870..830a5389 100644 --- a/account_move_name_sequence/readme/CONFIGURE.rst +++ b/account_move_name_sequence/readme/CONFIGURE.rst @@ -1,5 +1,5 @@ On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal. -On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds. +On sale and purchase journals, you have an additional option to have another sequence dedicated to refunds. Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option *Dedicated Credit Note Sequence* on existing sale and purchase journals if you don't want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry. diff --git a/account_move_name_sequence/readme/CONTRIBUTORS.rst b/account_move_name_sequence/readme/CONTRIBUTORS.rst index c3f90701..3e871242 100644 --- a/account_move_name_sequence/readme/CONTRIBUTORS.rst +++ b/account_move_name_sequence/readme/CONTRIBUTORS.rst @@ -1,2 +1,3 @@ * Alexis de Lattre * Moisés López +* Francisco Luna diff --git a/account_move_name_sequence/views/account_journal.xml b/account_move_name_sequence/views/account_journal.xml index d274975a..e0a28adc 100644 --- a/account_move_name_sequence/views/account_journal.xml +++ b/account_move_name_sequence/views/account_journal.xml @@ -2,6 +2,8 @@ diff --git a/account_move_name_sequence/views/account_move.xml b/account_move_name_sequence/views/account_move.xml index cb945731..2536e906 100644 --- a/account_move_name_sequence/views/account_move.xml +++ b/account_move_name_sequence/views/account_move.xml @@ -10,23 +10,21 @@ account.move - - {'invisible': [('name', '=', '/')]} - - {'invisible': [('name', '=', '/')]} + + - {'readonly': 1} - - + {'readonly': 1} + + {'invisible': 1} - + From 7f1c4ba12dab0f04163e3985507e12d1d9dbbbe7 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 26 May 2022 19:27:25 +0000 Subject: [PATCH 22/34] [UPD] README.rst --- account_move_name_sequence/README.rst | 8 ++++++-- account_move_name_sequence/static/description/index.html | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst index 07ddb325..8811eb96 100644 --- a/account_move_name_sequence/README.rst +++ b/account_move_name_sequence/README.rst @@ -98,7 +98,7 @@ Configuration On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal. -On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds. +On sale and purchase journals, you have an additional option to have another sequence dedicated to refunds. Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option *Dedicated Credit Note Sequence* on existing sale and purchase journals if you don't want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry. @@ -126,6 +126,7 @@ Contributors * Alexis de Lattre * Moisés López +* Francisco Luna Maintainers ~~~~~~~~~~~ @@ -146,10 +147,13 @@ promote its widespread use. .. |maintainer-moylop260| image:: https://github.com/moylop260.png?size=40px :target: https://github.com/moylop260 :alt: moylop260 +.. |maintainer-frahikLV| image:: https://github.com/frahikLV.png?size=40px + :target: https://github.com/frahikLV + :alt: frahikLV Current `maintainers `__: -|maintainer-alexis-via| |maintainer-moylop260| +|maintainer-alexis-via| |maintainer-moylop260| |maintainer-frahikLV| This module is part of the `OCA/account-financial-tools `_ project on GitHub. diff --git a/account_move_name_sequence/static/description/index.html b/account_move_name_sequence/static/description/index.html index 1f7fcb01..14a7905a 100644 --- a/account_move_name_sequence/static/description/index.html +++ b/account_move_name_sequence/static/description/index.html @@ -440,7 +440,7 @@ And even if you must use no-gap in your company or country it will reduce the co

Configuration

On the form view of an account journal, in the first tab, there is a many2one link to the sequence. When you create a new journal, you can keep this field empty and a new sequence will be automatically created when you save the journal.

-

On sale and purchase journals, you have an additionnal option to have another sequence dedicated to refunds.

+

On sale and purchase journals, you have an additional option to have another sequence dedicated to refunds.

Upon module installation, all existing journals will be updated with a journal entry sequence (and also a credit note sequence for sale and purchase journals). You should update the configuration of the sequences to fit your needs. You can uncheck the option Dedicated Credit Note Sequence on existing sale and purchase journals if you don’t want it. For the journals which already have journal entries, you should update the sequence configuration to avoid a discontinuity in the numbering for the next journal entry.

@@ -465,6 +465,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
@@ -475,7 +476,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome mission is to support the collaborative development of Odoo features and promote its widespread use.

Current maintainers:

-

alexis-via moylop260

+

alexis-via moylop260 frahikLV

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

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

From 3a1b342a62ba4e280b66e1f094df7cdcd5fc34ae Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 26 May 2022 19:27:25 +0000 Subject: [PATCH 23/34] account_move_name_sequence 14.0.1.2.2 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 1859ae30..46ab257a 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.2.1", + "version": "14.0.1.2.2", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From a800db0440cacfcfca74c35bd21c49e28c657be3 Mon Sep 17 00:00:00 2001 From: Francisco Javier Luna Vazquez Date: Thu, 26 May 2022 16:20:43 -0500 Subject: [PATCH 24/34] [MIG] account_move_name_sequence: Migration to 15.0 --- account_move_name_sequence/__manifest__.py | 2 +- .../models/account_journal.py | 34 ++++++++------- account_move_name_sequence/post_install.py | 42 +++++++++---------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index 46ab257a..de8ebb9b 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Account Move Number Sequence", - "version": "14.0.1.2.2", + "version": "15.0.1.0.0", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index 41755ee1..9038ec2a 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -2,6 +2,7 @@ # Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre # @author: Moisés López +# @author: Francisco Luna # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging @@ -45,26 +46,26 @@ class AccountJournal(models.Model): raise ValidationError( _( "On journal '%s', the same sequence is used as " - "Entry Sequence and Credit Note Entry Sequence." + "Entry Sequence and Credit Note Entry Sequence.", + journal.display_name, ) - % journal.display_name ) if journal.sequence_id and not journal.sequence_id.company_id: - raise ValidationError( - _( - "The company is not set on sequence '%s' configured on " - "journal '%s'." - ) - % (journal.sequence_id.display_name, journal.display_name) + msg = _( + "The company is not set on sequence '%(sequence)s' configured on " + "journal '%(journal)s'.", + sequence=journal.sequence_id.display_name, + journal=journal.display_name, ) + raise ValidationError(msg) if journal.refund_sequence_id and not journal.refund_sequence_id.company_id: - raise ValidationError( - _( - "The company is not set on sequence '%s' configured as " - "credit note sequence of journal '%s'." - ) - % (journal.refund_sequence_id.display_name, journal.display_name) + msg = _( + "The company is not set on sequence '%(sequence)s' configured as " + "credit note sequence of journal '%(journal)s'.", + sequence=journal.refund_sequence_id.display_name, + journal=journal.display_name, ) + raise ValidationError(msg) @api.model def create(self, vals): @@ -180,7 +181,10 @@ class AccountJournal(models.Model): ) select_max_number = ( "MAX(split_part(name, '%s', %d)::INTEGER) AS max_number" - % (prefixes[-1], prefixes.count(prefixes[-1]) + 1) + % ( + prefixes[-1], + prefixes.count(prefixes[-1]) + 1, + ) ) query = ( "SELECT %s, %s, %s FROM account_move " diff --git a/account_move_name_sequence/post_install.py b/account_move_name_sequence/post_install.py index ef52eeeb..10a69f0e 100644 --- a/account_move_name_sequence/post_install.py +++ b/account_move_name_sequence/post_install.py @@ -2,31 +2,31 @@ # Copyright 2022 Vauxoo (https://www.vauxoo.com/) # @author: Alexis de Lattre # @author: Moisés López +# @author: Francisco Luna # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import SUPERUSER_ID, api def create_journal_sequences(cr, registry): - with api.Environment.manage(): - env = api.Environment(cr, SUPERUSER_ID, {}) - journals = ( - env["account.journal"] - .with_context(active_test=False) - .search([("sequence_id", "=", False)]) - ) - for journal in journals: - journal_vals = { - "code": journal.code, - "name": journal.name, - "company_id": journal.company_id.id, - } - seq_vals = journal._prepare_sequence(journal_vals) - seq_vals.update(journal._prepare_sequence_current_moves()) - vals = {"sequence_id": env["ir.sequence"].create(seq_vals).id} - if journal.type in ("sale", "purchase") and journal.refund_sequence: - rseq_vals = journal._prepare_sequence(journal_vals, refund=True) - rseq_vals.update(journal._prepare_sequence_current_moves(refund=True)) - vals["refund_sequence_id"] = env["ir.sequence"].create(rseq_vals).id - journal.write(vals) + env = api.Environment(cr, SUPERUSER_ID, {}) + journals = ( + env["account.journal"] + .with_context(active_test=False) + .search([("sequence_id", "=", False)]) + ) + for journal in journals: + journal_vals = { + "code": journal.code, + "name": journal.name, + "company_id": journal.company_id.id, + } + seq_vals = journal._prepare_sequence(journal_vals) + seq_vals.update(journal._prepare_sequence_current_moves()) + vals = {"sequence_id": env["ir.sequence"].create(seq_vals).id} + if journal.type in ("sale", "purchase") and journal.refund_sequence: + rseq_vals = journal._prepare_sequence(journal_vals, refund=True) + rseq_vals.update(journal._prepare_sequence_current_moves(refund=True)) + vals["refund_sequence_id"] = env["ir.sequence"].create(rseq_vals).id + journal.write(vals) return From 198724234a13a46dfa6acc86e995ad8cf5f4c7db Mon Sep 17 00:00:00 2001 From: Francisco Javier Luna Vazquez Date: Wed, 25 May 2022 17:58:09 -0500 Subject: [PATCH 25/34] [FIX] account_move_name_sequence: Exclude no_gap sequences from _is_end_of_seq_chain --- .../models/account_move.py | 9 +++++++ .../tests/test_account_move_name_seq.py | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py index ff1dbc75..6f63aab6 100644 --- a/account_move_name_sequence/models/account_move.py +++ b/account_move_name_sequence/models/account_move.py @@ -52,3 +52,12 @@ class AccountMove(models.Model): # We must by-pass this constraint of sequence.mixin def _constrains_date_sequence(self): return True + + def _is_end_of_seq_chain(self): + invoices_no_gap_sequences = self.filtered( + lambda inv: inv.journal_id.sequence_id.implementation == "no_gap" + ) + invoices_other_sequences = self - invoices_no_gap_sequences + if not invoices_other_sequences and invoices_no_gap_sequences: + return False + return super(AccountMove, invoices_other_sequences)._is_end_of_seq_chain() diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py index c6acf33c..039cfc87 100644 --- a/account_move_name_sequence/tests/test_account_move_name_seq.py +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -1,10 +1,13 @@ # Copyright 2021 Akretion France (http://www.akretion.com/) # @author: Alexis de Lattre +# @author: Moisés López +# @author: Francisco Luna # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from datetime import datetime from odoo import fields +from odoo.exceptions import UserError from odoo.tests import tagged from odoo.tests.common import TransactionCase @@ -111,3 +114,25 @@ class TestAccountMoveNameSequence(TransactionCase): in_refund_invoice.button_draft() in_refund_invoice.action_post() self.assertEqual(in_refund_invoice.name, move_name) + + def test_remove_invoice_error(self): + invoice = self.env["account.move"].create( + { + "date": self.date, + "journal_id": self.misc_journal.id, + "line_ids": [ + (0, 0, {"account_id": self.account1.id, "debit": 10}), + (0, 0, {"account_id": self.account2.id, "credit": 10}), + ], + } + ) + self.assertEqual(invoice.name, "/") + invoice.action_post() + error_msg = "You cannot delete an item linked to a posted entry." + with self.assertRaisesRegex(UserError, error_msg): + invoice.unlink() + invoice.button_draft() + invoice.button_cancel() + error_msg = "You cannot delete this entry, as it has already consumed a" + with self.assertRaisesRegex(UserError, error_msg): + invoice.unlink() From ad207c5f13428e442d0085f6a349f6306a680343 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 26 May 2022 22:12:11 +0000 Subject: [PATCH 26/34] [UPD] Update account_move_name_sequence.pot --- .../i18n/account_move_name_sequence.pot | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/account_move_name_sequence/i18n/account_move_name_sequence.pot b/account_move_name_sequence/i18n/account_move_name_sequence.pot index 395f8e18..b9aa2fba 100644 --- a/account_move_name_sequence/i18n/account_move_name_sequence.pot +++ b/account_move_name_sequence/i18n/account_move_name_sequence.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -37,13 +37,6 @@ msgstr "" msgid "Dedicated Credit Note Sequence" msgstr "" -#. module: account_move_name_sequence -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__display_name -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__display_name -#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence__display_name -msgid "Display Name" -msgstr "" - #. module: account_move_name_sequence #: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__sequence_id msgid "Entry Sequence" @@ -56,13 +49,6 @@ msgstr "" msgid "Highest Name" msgstr "" -#. module: account_move_name_sequence -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal__id -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__id -#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence__id -msgid "ID" -msgstr "" - #. module: account_move_name_sequence #: model:ir.model,name:account_move_name_sequence.model_account_journal msgid "Journal" @@ -73,13 +59,6 @@ msgstr "" msgid "Journal Entry" msgstr "" -#. module: account_move_name_sequence -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_journal____last_update -#: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move____last_update -#: model:ir.model.fields,field_description:account_move_name_sequence.field_ir_sequence____last_update -msgid "Last Modified on" -msgstr "" - #. module: account_move_name_sequence #: model:ir.model.fields,field_description:account_move_name_sequence.field_account_bank_statement_line__name #: model:ir.model.fields,field_description:account_move_name_sequence.field_account_move__name @@ -126,14 +105,16 @@ msgstr "" #: code:addons/account_move_name_sequence/models/account_journal.py:0 #, python-format msgid "" -"The company is not set on sequence '%s' configured as credit note sequence " -"of journal '%s'." +"The company is not set on sequence '%(sequence)s' configured as credit note " +"sequence of journal '%(journal)s'." msgstr "" #. module: account_move_name_sequence #: code:addons/account_move_name_sequence/models/account_journal.py:0 #, python-format -msgid "The company is not set on sequence '%s' configured on journal '%s'." +msgid "" +"The company is not set on sequence '%(sequence)s' configured on journal " +"'%(journal)s'." msgstr "" #. module: account_move_name_sequence From b70341d040c5c5b1edde48cfddb9387e23ad14b2 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 26 May 2022 22:16:28 +0000 Subject: [PATCH 27/34] [UPD] README.rst --- account_move_name_sequence/README.rst | 10 +++++----- .../static/description/index.html | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/account_move_name_sequence/README.rst b/account_move_name_sequence/README.rst index 8811eb96..0d9fe0a7 100644 --- a/account_move_name_sequence/README.rst +++ b/account_move_name_sequence/README.rst @@ -14,13 +14,13 @@ Account Move Number Sequence :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github - :target: https://github.com/OCA/account-financial-tools/tree/14.0/account_move_name_sequence + :target: https://github.com/OCA/account-financial-tools/tree/15.0/account_move_name_sequence :alt: OCA/account-financial-tools .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/account-financial-tools-14-0/account-financial-tools-14-0-account_move_name_sequence + :target: https://translation.odoo-community.org/projects/account-financial-tools-15-0/account-financial-tools-15-0-account_move_name_sequence :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/92/14.0 + :target: https://runbot.odoo-community.org/runbot/92/15.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -108,7 +108,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -155,6 +155,6 @@ Current `maintainers `__: |maintainer-alexis-via| |maintainer-moylop260| |maintainer-frahikLV| -This module is part of the `OCA/account-financial-tools `_ project on GitHub. +This module is part of the `OCA/account-financial-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_move_name_sequence/static/description/index.html b/account_move_name_sequence/static/description/index.html index 14a7905a..e0228198 100644 --- a/account_move_name_sequence/static/description/index.html +++ b/account_move_name_sequence/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/account-financial-tools Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/account-financial-tools Translate me on Weblate Try me on Runbot

In Odoo version 13.0 and previous versions, the number of journal entries was generated from a sequence configured on the journal.

In Odoo version 14.0, the number of journal entries can be manually set by the user. Then, the number attributed for the next journal entries in the same journal is computed by a complex piece of code that guesses the format of the journal entry number from the number of the journal entry which was manually entered by the user. It has several drawbacks:

    @@ -448,7 +448,7 @@ And even if you must use no-gap in your company or country it will reduce the co

    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.

    +feedback.

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

@@ -477,7 +477,7 @@ mission is to support the collaborative development of Odoo features and promote its widespread use.

Current maintainers:

alexis-via moylop260 frahikLV

-

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

+

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

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

From 6599bfd112331b9d8c618e8a3ddf40997514406e Mon Sep 17 00:00:00 2001 From: Pierre Verkest Date: Thu, 7 Jul 2022 16:56:27 +0200 Subject: [PATCH 28/34] [FIX] account_move_name_sequence: Use account move date to compute prefix In case you want name your invoice YYYY-MM-SEQ (ie: 2022-07-00001) where: * YYYY: is the account move year * MM: is the account move month * SEQ: is a numerical sequence that is continue along the fiscal year assuming fiscal year is over two years (ie: from july to june next year) Before this commit the sequence prefix use now() to be compute but the range is selected with the account move date. This commit make consistency computing prefix with the account move date as well. So account move manage the first janunary for the last day of the previous year will properly use the account move date. Co-authored-by: Alexis de Lattre --- .../models/account_move.py | 5 +- .../tests/test_account_move_name_seq.py | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py index 6f63aab6..8813263f 100644 --- a/account_move_name_sequence/models/account_move.py +++ b/account_move_name_sequence/models/account_move.py @@ -46,7 +46,10 @@ class AccountMove(models.Model): seq = move.journal_id.refund_sequence_id else: seq = move.journal_id.sequence_id - name = seq.next_by_id(sequence_date=move.date) + # next_by_id(date) only applies on ir.sequence.date_range selection + # => we use with_context(ir_sequence_date=date).next_by_id() + # which applies on ir.sequence.date_range selection AND prefix + name = seq.with_context(ir_sequence_date=move.date).next_by_id() move.name = name # We must by-pass this constraint of sequence.mixin diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py index 039cfc87..207ca613 100644 --- a/account_move_name_sequence/tests/test_account_move_name_seq.py +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -6,6 +6,8 @@ from datetime import datetime +from freezegun import freeze_time + from odoo import fields from odoo.exceptions import UserError from odoo.tests import tagged @@ -85,6 +87,57 @@ class TestAccountMoveNameSequence(TransactionCase): move.action_post() self.assertEqual(move.name, move_name) + def test_prefix_move_name_use_move_date(self): + seq = self.misc_journal.sequence_id + seq.prefix = "TEST-%(year)s-%(month)s-" + self.env["ir.sequence.date_range"].sudo().create( + { + "date_from": "2021-07-01", + "date_to": "2022-06-30", + "sequence_id": seq.id, + } + ) + with freeze_time("2022-01-01"): + move = self.env["account.move"].create( + { + "date": "2021-12-31", + "journal_id": self.misc_journal.id, + "line_ids": [ + (0, 0, {"account_id": self.account1.id, "debit": 10}), + (0, 0, {"account_id": self.account2.id, "credit": 10}), + ], + } + ) + move.action_post() + self.assertEqual(move.name, "TEST-2021-12-0001") + with freeze_time("2022-01-01"): + move = self.env["account.move"].create( + { + "date": "2022-06-30", + "journal_id": self.misc_journal.id, + "line_ids": [ + (0, 0, {"account_id": self.account1.id, "debit": 10}), + (0, 0, {"account_id": self.account2.id, "credit": 10}), + ], + } + ) + move.action_post() + self.assertEqual(move.name, "TEST-2022-06-0002") + + with freeze_time("2022-01-01"): + move = self.env["account.move"].create( + { + "date": "2022-07-01", + "journal_id": self.misc_journal.id, + "line_ids": [ + (0, 0, {"account_id": self.account1.id, "debit": 10}), + (0, 0, {"account_id": self.account2.id, "credit": 10}), + ], + } + ) + move.action_post() + self.assertEqual(move.name, "TEST-2022-07-0001") + def test_in_refund(self): in_refund_invoice = self.env["account.move"].create( { From d07e939fad00e249542dcba06db526caeb4d79c8 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sat, 9 Jul 2022 18:22:48 +0000 Subject: [PATCH 29/34] account_move_name_sequence 15.0.1.1.0 --- account_move_name_sequence/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index de8ebb9b..fec5f01f 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Account Move Number Sequence", - "version": "15.0.1.0.0", + "version": "15.0.1.1.0", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", From a07eeda085afcfeabe7fc9ea129b0bc4f18a9f3e Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 22 Nov 2022 14:37:48 +0100 Subject: [PATCH 30/34] [IMP] : pre-commit stuff --- .../odoo/addons/account_move_name_sequence | 1 + setup/account_move_name_sequence/setup.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 120000 setup/account_move_name_sequence/odoo/addons/account_move_name_sequence create mode 100644 setup/account_move_name_sequence/setup.py diff --git a/setup/account_move_name_sequence/odoo/addons/account_move_name_sequence b/setup/account_move_name_sequence/odoo/addons/account_move_name_sequence new file mode 120000 index 00000000..6eefb58d --- /dev/null +++ b/setup/account_move_name_sequence/odoo/addons/account_move_name_sequence @@ -0,0 +1 @@ +../../../../account_move_name_sequence \ No newline at end of file diff --git a/setup/account_move_name_sequence/setup.py b/setup/account_move_name_sequence/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/account_move_name_sequence/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 86eed6c1ed7e3d86d38f7e398ae6501ef50c43f3 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 24 Nov 2022 12:55:29 +0100 Subject: [PATCH 31/34] [MIG] account_move_name_sequence: Migration to 16.0 --- account_move_name_sequence/__manifest__.py | 2 +- .../models/account_journal.py | 23 ++++---- .../readme/CONTRIBUTORS.rst | 15 ++++- .../tests/test_account_move_name_seq.py | 56 ++++++++++++++++++- .../views/account_move.xml | 16 +++--- 5 files changed, 87 insertions(+), 25 deletions(-) diff --git a/account_move_name_sequence/__manifest__.py b/account_move_name_sequence/__manifest__.py index fec5f01f..d35084b3 100644 --- a/account_move_name_sequence/__manifest__.py +++ b/account_move_name_sequence/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Account Move Number Sequence", - "version": "15.0.1.1.0", + "version": "16.0.1.0.0", "category": "Accounting", "license": "AGPL-3", "summary": "Generate journal entry number from sequence", diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index 9038ec2a..3cfd1531 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -67,17 +67,18 @@ class AccountJournal(models.Model): ) raise ValidationError(msg) - @api.model - def create(self, vals): - if not vals.get("sequence_id"): - vals["sequence_id"] = self._create_sequence(vals).id - if ( - vals.get("type") in ("sale", "purchase") - and vals.get("refund_sequence") - and not vals.get("refund_sequence_id") - ): - vals["refund_sequence_id"] = self._create_sequence(vals, refund=True).id - return super().create(vals) + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if not vals.get("sequence_id"): + vals["sequence_id"] = self._create_sequence(vals).id + if ( + vals.get("type") in ("sale", "purchase") + and vals.get("refund_sequence") + and not vals.get("refund_sequence_id") + ): + vals["refund_sequence_id"] = self._create_sequence(vals, refund=True).id + return super().create(vals_list) @api.model def _prepare_sequence(self, vals, refund=False): diff --git a/account_move_name_sequence/readme/CONTRIBUTORS.rst b/account_move_name_sequence/readme/CONTRIBUTORS.rst index 3e871242..39d07df2 100644 --- a/account_move_name_sequence/readme/CONTRIBUTORS.rst +++ b/account_move_name_sequence/readme/CONTRIBUTORS.rst @@ -1,3 +1,12 @@ -* Alexis de Lattre -* Moisés López -* Francisco Luna +* `Akretion `_: + + * Alexis de Lattre + +* `Vauxoo `_: + + * Moisés López + * Francisco Luna + +* `Factor Libre `_: + + * Rodrigo Bonilla Martinez diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py index 207ca613..4538ccd5 100644 --- a/account_move_name_sequence/tests/test_account_move_name_seq.py +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -9,7 +9,7 @@ from datetime import datetime from freezegun import freeze_time from odoo import fields -from odoo.exceptions import UserError +from odoo.exceptions import UserError, ValidationError from odoo.tests import tagged from odoo.tests.common import TransactionCase @@ -168,7 +168,7 @@ class TestAccountMoveNameSequence(TransactionCase): in_refund_invoice.action_post() self.assertEqual(in_refund_invoice.name, move_name) - def test_remove_invoice_error(self): + def test_remove_invoice_error_secuence_no_grap(self): invoice = self.env["account.move"].create( { "date": self.date, @@ -189,3 +189,55 @@ class TestAccountMoveNameSequence(TransactionCase): error_msg = "You cannot delete this entry, as it has already consumed a" with self.assertRaisesRegex(UserError, error_msg): invoice.unlink() + + def test_remove_invoice_error_secuence_standard(self): + implementation = {"implementation": "standard"} + self.purchase_journal.sequence_id.write(implementation) + self.purchase_journal.refund_sequence_id.write(implementation) + in_refund_invoice = self.env["account.move"].create( + { + "journal_id": self.purchase_journal.id, + "invoice_date": self.date, + "partner_id": self.env.ref("base.res_partner_3").id, + "move_type": "in_refund", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account1.id, + "price_unit": 42.0, + "quantity": 12, + }, + ) + ], + } + ) + in_refund_invoice._compute_split_sequence() + self.assertEqual(in_refund_invoice.name, "/") + in_refund_invoice.action_post() + error_msg = "You cannot delete an item linked to a posted entry." + with self.assertRaisesRegex(UserError, error_msg): + in_refund_invoice.unlink() + in_refund_invoice.button_draft() + in_refund_invoice.button_cancel() + self.assertTrue(in_refund_invoice.unlink()) + + def test_journal_check_journal_sequence(self): + new_journal = self.purchase_journal.copy() + # same sequence_id and refund_sequence_id + with self.assertRaises(ValidationError): + new_journal.write({"refund_sequence_id": new_journal.sequence_id}) + + # company_id in sequence_id or refund_sequence_id to False + new_sequence_id = new_journal.sequence_id.copy({"company_id": False}) + new_refund_sequence_id = new_journal.refund_sequence_id.copy( + {"company_id": False} + ) + with self.assertRaises(ValidationError): + new_journal.write({"sequence_id": new_sequence_id.id}) + with self.assertRaises(ValidationError): + new_journal.write({"refund_sequence_id": new_refund_sequence_id.id}) + + def test_constrains_date_sequence_true(self): + self.assertTrue(self.env["account.move"]._constrains_date_sequence()) diff --git a/account_move_name_sequence/views/account_move.xml b/account_move_name_sequence/views/account_move.xml index 2536e906..c537b17a 100644 --- a/account_move_name_sequence/views/account_move.xml +++ b/account_move_name_sequence/views/account_move.xml @@ -10,20 +10,20 @@ account.move - - {'invisible': [('name', '=', '/')]} + + 1 - {'readonly': 1} + {'invisible': [('name', '=', '/')]} + 1 - - {'invisible': 1} + + {'invisible': ['|', ('state', '!=', 'draft'), ('name', '!=', '/')]} From 2d5f794ed531d41608d19b1c7eb8ff09e5fa670c Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 24 Nov 2022 14:13:50 +0100 Subject: [PATCH 32/34] [FIX] account_move_name_sequence: return sequence names do not add a space between name and returns. --- account_move_name_sequence/models/account_journal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index 3cfd1531..ab3e275c 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -86,7 +86,7 @@ class AccountJournal(models.Model): prefix = "%s%s/%%(range_year)s/" % (refund and "R" or "", code) seq_vals = { "name": "%s%s" - % (vals.get("name", _("Sequence")), refund and _("Refund") + " " or ""), + % (vals.get("name", _("Sequence")), refund and " " + _("Refund") or ""), "company_id": vals.get("company_id") or self.env.company.id, "implementation": "no_gap", "prefix": prefix, From 346eb9d0852f9c4624c9fe70991c2c127d4393e0 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 28 Nov 2022 10:46:08 +0100 Subject: [PATCH 33/34] [FIX] account_move_name_sequence: issue #1465 vals get refund_sequence true if value not get in vals --- account_move_name_sequence/models/account_journal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_move_name_sequence/models/account_journal.py b/account_move_name_sequence/models/account_journal.py index ab3e275c..3531cb80 100644 --- a/account_move_name_sequence/models/account_journal.py +++ b/account_move_name_sequence/models/account_journal.py @@ -74,7 +74,7 @@ class AccountJournal(models.Model): vals["sequence_id"] = self._create_sequence(vals).id if ( vals.get("type") in ("sale", "purchase") - and vals.get("refund_sequence") + and vals.get("refund_sequence", True) and not vals.get("refund_sequence_id") ): vals["refund_sequence_id"] = self._create_sequence(vals, refund=True).id From ab8e59d69d993fea3dba32c324035b43f0cd3840 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 2 Dec 2022 12:57:26 +0100 Subject: [PATCH 34/34] [FIX] account_move_name_sequence: call flush before _fetch_duplicate_supplier_reference method same issue https://github.com/OCA/account-financial-tools/issues/1501 this fix not working for v16 https://github.com/OCA/account-financial-tools/pull/1514 --- .../models/account_move.py | 6 ++ .../tests/test_account_move_name_seq.py | 96 +++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/account_move_name_sequence/models/account_move.py b/account_move_name_sequence/models/account_move.py index 8813263f..8b43a629 100644 --- a/account_move_name_sequence/models/account_move.py +++ b/account_move_name_sequence/models/account_move.py @@ -64,3 +64,9 @@ class AccountMove(models.Model): if not invoices_other_sequences and invoices_no_gap_sequences: return False return super(AccountMove, invoices_other_sequences)._is_end_of_seq_chain() + + def _fetch_duplicate_supplier_reference(self, only_posted=False): + moves = self.filtered(lambda m: m.is_purchase_document() and m.ref) + if moves: + self.flush_model(["name", "journal_id", "move_type", "state"]) + return super()._fetch_duplicate_supplier_reference(only_posted=only_posted) diff --git a/account_move_name_sequence/tests/test_account_move_name_seq.py b/account_move_name_sequence/tests/test_account_move_name_seq.py index 4538ccd5..4457da0c 100644 --- a/account_move_name_sequence/tests/test_account_move_name_seq.py +++ b/account_move_name_sequence/tests/test_account_move_name_seq.py @@ -138,6 +138,102 @@ class TestAccountMoveNameSequence(TransactionCase): move.action_post() self.assertEqual(move.name, "TEST-2022-07-0001") + def test_in_invoice_and_refund(self): + in_invoice = self.env["account.move"].create( + { + "journal_id": self.purchase_journal.id, + "invoice_date": self.date, + "partner_id": self.env.ref("base.res_partner_3").id, + "move_type": "in_invoice", + "invoice_line_ids": [ + ( + 0, + 0, + { + "account_id": self.account1.id, + "price_unit": 42.0, + "quantity": 12, + }, + ), + ( + 0, + 0, + { + "account_id": self.account1.id, + "price_unit": 48.0, + "quantity": 10, + }, + ), + ], + } + ) + self.assertEqual(in_invoice.name, "/") + in_invoice.action_post() + + move_reversal = ( + self.env["account.move.reversal"] + .with_context(active_model="account.move", active_ids=in_invoice.ids) + .create( + { + "journal_id": in_invoice.journal_id.id, + "reason": "no reason", + "refund_method": "cancel", + } + ) + ) + reversal = move_reversal.reverse_moves() + reversed_move = self.env["account.move"].browse(reversal["res_id"]) + self.assertTrue(reversed_move) + self.assertEqual(reversed_move.state, "posted") + + in_invoice = in_invoice.copy( + { + "invoice_date": self.date, + } + ) + in_invoice.action_post() + + move_reversal = ( + self.env["account.move.reversal"] + .with_context(active_model="account.move", active_ids=in_invoice.ids) + .create( + { + "journal_id": in_invoice.journal_id.id, + "reason": "no reason", + "refund_method": "modify", + } + ) + ) + reversal = move_reversal.reverse_moves() + draft_invoice = self.env["account.move"].browse(reversal["res_id"]) + self.assertTrue(draft_invoice) + self.assertEqual(draft_invoice.state, "draft") + self.assertEqual(draft_invoice.move_type, "in_invoice") + + in_invoice = in_invoice.copy( + { + "invoice_date": self.date, + } + ) + in_invoice.action_post() + + move_reversal = ( + self.env["account.move.reversal"] + .with_context(active_model="account.move", active_ids=in_invoice.ids) + .create( + { + "journal_id": in_invoice.journal_id.id, + "reason": "no reason", + "refund_method": "refund", + } + ) + ) + reversal = move_reversal.reverse_moves() + draft_reversed_move = self.env["account.move"].browse(reversal["res_id"]) + self.assertTrue(draft_reversed_move) + self.assertEqual(draft_reversed_move.state, "draft") + self.assertEqual(draft_reversed_move.move_type, "in_refund") + def test_in_refund(self): in_refund_invoice = self.env["account.move"].create( {