diff --git a/account_journal_general_sequence/__manifest__.py b/account_journal_general_sequence/__manifest__.py
index 39bfb62c..6a4b99d8 100644
--- a/account_journal_general_sequence/__manifest__.py
+++ b/account_journal_general_sequence/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "General sequence in account journals",
"summary": "Add configurable sequence to account moves, per journal",
- "version": "16.0.1.1.0",
+ "version": "16.0.2.0.0",
"category": "Accounting/Accounting",
"website": "https://github.com/OCA/account-financial-tools",
"author": "Moduon, Odoo Community Association (OCA)",
diff --git a/account_journal_general_sequence/migrations/16.0.2.0.0/post-migration.py b/account_journal_general_sequence/migrations/16.0.2.0.0/post-migration.py
new file mode 100644
index 00000000..a17d1baf
--- /dev/null
+++ b/account_journal_general_sequence/migrations/16.0.2.0.0/post-migration.py
@@ -0,0 +1,44 @@
+# Copyright 2023 Moduon Team S.L.
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3.0)
+from odoo import SUPERUSER_ID, api, fields
+
+
+def migrate(cr, version):
+ """One journal sequence per company."""
+ env = api.Environment(cr, SUPERUSER_ID, {})
+ journals = env["account.journal"].search(
+ [
+ (
+ "entry_number_sequence_id.code",
+ "=",
+ "account_journal_general_sequence.default",
+ )
+ ]
+ )
+ for journal in journals:
+ if journal.company_id != journal.entry_number_sequence_id.company_id:
+ new_sequence = env["ir.sequence"].search(
+ [
+ ("code", "=", "account_journal_general_sequence.default"),
+ ("company_id", "=", journal.company_id.id),
+ ]
+ ) or journal.entry_number_sequence_id.copy(
+ {
+ "company_id": journal.company_id.id,
+ "name": "{} ({})".format(
+ journal.entry_number_sequence_id.name, journal.company_id.name
+ ),
+ "number_next_actual": journal.entry_number_sequence_id.number_next_actual,
+ "date_range_ids": [
+ fields.Command.create(
+ {
+ "date_from": rng.date_from,
+ "date_to": rng.date_to,
+ "number_next_actual": rng.number_next_actual,
+ }
+ )
+ for rng in journal.entry_number_sequence_id.date_range_ids
+ ],
+ }
+ )
+ journal.entry_number_sequence_id = new_sequence
diff --git a/account_journal_general_sequence/models/account_journal.py b/account_journal_general_sequence/models/account_journal.py
index c36eb153..6a6feb42 100644
--- a/account_journal_general_sequence/models/account_journal.py
+++ b/account_journal_general_sequence/models/account_journal.py
@@ -2,7 +2,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import logging
-from odoo import _, fields, models
+from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
@@ -13,27 +13,40 @@ class AccountJournal(models.Model):
entry_number_sequence_id = fields.Many2one(
comodel_name="ir.sequence",
string="Account entry number sequence",
- default=lambda self: self._default_entry_number_sequence(),
+ compute="_compute_entry_number_sequence",
+ domain="[('company_id', '=', company_id)]",
+ check_company=True,
+ readonly=False,
+ store=True,
copy=False,
help="Sequence used for account entry numbering.",
)
+ entry_number_sequence_id_name = fields.Char(related="entry_number_sequence_id.code")
- def _default_entry_number_sequence(self):
+ @api.depends("company_id")
+ def _compute_entry_number_sequence(self):
"""Get the default sequence for all journals."""
- result = self.env["ir.sequence"].search(
- [("code", "=", "account_journal_general_sequence.default")]
- )
- if result:
- return result
- _logger.info("Creating default sequence for account move numbers")
- result = self.env["ir.sequence"].create(
- {
- "name": _("Account entry default numbering"),
- "code": "account_journal_general_sequence.default",
- "implementation": "no_gap",
- "prefix": "%(range_year)s/",
- "padding": 10,
- "use_date_range": True,
- }
- )
- return result
+ for one in self:
+ sequence = self.env["ir.sequence"].search(
+ [
+ ("code", "=", "account_journal_general_sequence.default"),
+ ("company_id", "=", one.company_id.id),
+ ]
+ )
+ if not sequence:
+ _logger.info("Creating default sequence for account move numbers")
+ sequence = self.env["ir.sequence"].create(
+ {
+ "name": _(
+ "Account entry default numbering (%s)",
+ one.company_id.name,
+ ),
+ "code": "account_journal_general_sequence.default",
+ "company_id": one.company_id.id,
+ "implementation": "no_gap",
+ "prefix": "%(range_year)s/",
+ "padding": 8,
+ "use_date_range": True,
+ }
+ )
+ one.entry_number_sequence_id = sequence
diff --git a/account_journal_general_sequence/tests/test_numbering.py b/account_journal_general_sequence/tests/test_numbering.py
index b8c9f86b..8087a499 100644
--- a/account_journal_general_sequence/tests/test_numbering.py
+++ b/account_journal_general_sequence/tests/test_numbering.py
@@ -2,6 +2,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from freezegun import freeze_time
+from odoo.fields import Command
from odoo.tests.common import Form, new_test_user, tagged, users
from odoo.tools import mute_logger
@@ -14,11 +15,18 @@ class RenumberCase(TestAccountReconciliationCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
+ companies = cls.company_data["company"] | cls.company_data_2["company"]
cls.invoicer = new_test_user(
- cls.env, "test_invoicer", "account.group_account_invoice"
+ cls.env,
+ "test_invoicer",
+ "account.group_account_invoice",
+ company_ids=[Command.set(companies.ids)],
)
cls.manager = new_test_user(
- cls.env, "test_manager", "account.group_account_manager"
+ cls.env,
+ "test_manager",
+ "account.group_account_manager",
+ company_ids=[Command.set(companies.ids)],
)
@users("test_invoicer")
@@ -42,18 +50,22 @@ class RenumberCase(TestAccountReconciliationCommon):
next_year_invoice = self._create_invoice(
date_invoice="2023-12-31", auto_validate=True
)
- next_year_invoice.flush(["entry_number"], next_year_invoice)
+ next_year_invoice.flush_recordset(["entry_number"])
new_invoice = self._create_invoice(
date_invoice="2022-05-10", auto_validate=True
)
- new_invoice.flush(["entry_number"], new_invoice)
+ new_invoice.flush_recordset(["entry_number"])
old_invoice = self._create_invoice(
date_invoice="2022-04-30", auto_validate=True
)
- old_invoice.flush(["entry_number"], old_invoice)
+ old_invoice.flush_recordset(["entry_number"])
self.assertLess(new_invoice.entry_number, old_invoice.entry_number)
# Fix entry number order with wizard; default values are OK
- wiz_f = Form(self.env["account.move.renumber.wizard"])
+ wiz_f = Form(
+ self.env["account.move.renumber.wizard"].with_company(
+ self.company_data["company"]
+ )
+ )
self.assertEqual(len(wiz_f.available_sequence_ids), 1)
wiz = wiz_f.save()
wiz.action_renumber()
@@ -67,10 +79,10 @@ class RenumberCase(TestAccountReconciliationCommon):
wiz_f = Form(self.env["account.move.renumber.wizard"])
wiz = wiz_f.save()
wiz.action_renumber()
- self.assertEqual(opening_invoice.entry_number, "2022/0000000001")
- self.assertEqual(old_invoice.entry_number, "2022/0000000002")
- self.assertEqual(new_invoice.entry_number, "2022/0000000003")
- self.assertEqual(next_year_invoice.entry_number, "2023/0000000001")
+ self.assertEqual(opening_invoice.entry_number, "2022/00000001")
+ self.assertEqual(old_invoice.entry_number, "2022/00000002")
+ self.assertEqual(new_invoice.entry_number, "2022/00000003")
+ self.assertEqual(next_year_invoice.entry_number, "2023/00000001")
@users("test_invoicer")
def test_install_no_entry_number(self):
@@ -88,3 +100,21 @@ class RenumberCase(TestAccountReconciliationCommon):
invoice.action_post()
# Ensure there's no entry number
self.assertFalse(invoice.entry_number)
+
+ @users("test_invoicer")
+ def test_new_company_journal(self):
+ # Create new companies
+ cmp1 = self.company_data["company"]
+ cmp2 = self.company_data_2["company"]
+ # Create a new invoice for each company
+ self.env = self.env(
+ context=dict(self.env.context, allowed_company_ids=cmp1.ids)
+ )
+ invoice1 = self.create_invoice()
+ self.env = self.env(
+ context=dict(self.env.context, allowed_company_ids=cmp2.ids)
+ )
+ invoice2 = self.create_invoice()
+ # Each company has a different sequence, so the entry number should be the same
+ self.assertEqual(invoice1.entry_number, "2022/00000001")
+ self.assertEqual(invoice2.entry_number, "2022/00000001")
diff --git a/account_journal_general_sequence/views/account_journal.xml b/account_journal_general_sequence/views/account_journal.xml
index 13f8e690..d38116b8 100644
--- a/account_journal_general_sequence/views/account_journal.xml
+++ b/account_journal_general_sequence/views/account_journal.xml
@@ -20,7 +20,11 @@
-
+
+
diff --git a/account_journal_general_sequence/wizards/account_move_renumber_wizard.py b/account_journal_general_sequence/wizards/account_move_renumber_wizard.py
index ff261c41..ac9cacdd 100644
--- a/account_journal_general_sequence/wizards/account_move_renumber_wizard.py
+++ b/account_journal_general_sequence/wizards/account_move_renumber_wizard.py
@@ -41,13 +41,21 @@ class AccountMoveRenumberWizard(models.TransientModel):
def _default_entry_number_sequence(self):
"""Get default sequence if it exists."""
return self.env["ir.sequence"].search(
- [("code", "=", "account_journal_general_sequence.default")]
+ [
+ "&",
+ ("code", "=", "account_journal_general_sequence.default"),
+ ("company_id", "in", self.env.companies.ids),
+ ]
)
@api.model
def _default_available_sequence_ids(self):
"""Let view display only journal-related sequences."""
- return self.env["account.journal"].search([]).mapped("entry_number_sequence_id")
+ return (
+ self.env["account.journal"]
+ .search([("company_id", "in", self.env.companies.ids)])
+ .mapped("entry_number_sequence_id")
+ )
def action_renumber(self):
"""Renumber moves.