2
0

Merge PR #1665 into 16.0

Signed-off-by rafaelbn
This commit is contained in:
OCA-git-bot 2023-06-30 16:50:15 +00:00
commit 358925d8ce
6 changed files with 133 additions and 34 deletions

View File

@ -3,7 +3,7 @@
{ {
"name": "General sequence in account journals", "name": "General sequence in account journals",
"summary": "Add configurable sequence to account moves, per journal", "summary": "Add configurable sequence to account moves, per journal",
"version": "16.0.1.1.0", "version": "16.0.2.0.0",
"category": "Accounting/Accounting", "category": "Accounting/Accounting",
"website": "https://github.com/OCA/account-financial-tools", "website": "https://github.com/OCA/account-financial-tools",
"author": "Moduon, Odoo Community Association (OCA)", "author": "Moduon, Odoo Community Association (OCA)",

View File

@ -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

View File

@ -2,7 +2,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import logging import logging
from odoo import _, fields, models from odoo import _, api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -13,27 +13,40 @@ class AccountJournal(models.Model):
entry_number_sequence_id = fields.Many2one( entry_number_sequence_id = fields.Many2one(
comodel_name="ir.sequence", comodel_name="ir.sequence",
string="Account entry number 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, copy=False,
help="Sequence used for account entry numbering.", 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.""" """Get the default sequence for all journals."""
result = self.env["ir.sequence"].search( for one in self:
[("code", "=", "account_journal_general_sequence.default")] sequence = self.env["ir.sequence"].search(
) [
if result: ("code", "=", "account_journal_general_sequence.default"),
return result ("company_id", "=", one.company_id.id),
_logger.info("Creating default sequence for account move numbers") ]
result = self.env["ir.sequence"].create( )
{ if not sequence:
"name": _("Account entry default numbering"), _logger.info("Creating default sequence for account move numbers")
"code": "account_journal_general_sequence.default", sequence = self.env["ir.sequence"].create(
"implementation": "no_gap", {
"prefix": "%(range_year)s/", "name": _(
"padding": 10, "Account entry default numbering (%s)",
"use_date_range": True, one.company_id.name,
} ),
) "code": "account_journal_general_sequence.default",
return result "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

View File

@ -2,6 +2,7 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from freezegun import freeze_time from freezegun import freeze_time
from odoo.fields import Command
from odoo.tests.common import Form, new_test_user, tagged, users from odoo.tests.common import Form, new_test_user, tagged, users
from odoo.tools import mute_logger from odoo.tools import mute_logger
@ -14,11 +15,18 @@ class RenumberCase(TestAccountReconciliationCommon):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
companies = cls.company_data["company"] | cls.company_data_2["company"]
cls.invoicer = new_test_user( 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.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") @users("test_invoicer")
@ -42,18 +50,22 @@ class RenumberCase(TestAccountReconciliationCommon):
next_year_invoice = self._create_invoice( next_year_invoice = self._create_invoice(
date_invoice="2023-12-31", auto_validate=True 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( new_invoice = self._create_invoice(
date_invoice="2022-05-10", auto_validate=True 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( old_invoice = self._create_invoice(
date_invoice="2022-04-30", auto_validate=True 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) self.assertLess(new_invoice.entry_number, old_invoice.entry_number)
# Fix entry number order with wizard; default values are OK # 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) self.assertEqual(len(wiz_f.available_sequence_ids), 1)
wiz = wiz_f.save() wiz = wiz_f.save()
wiz.action_renumber() wiz.action_renumber()
@ -67,10 +79,10 @@ class RenumberCase(TestAccountReconciliationCommon):
wiz_f = Form(self.env["account.move.renumber.wizard"]) wiz_f = Form(self.env["account.move.renumber.wizard"])
wiz = wiz_f.save() wiz = wiz_f.save()
wiz.action_renumber() wiz.action_renumber()
self.assertEqual(opening_invoice.entry_number, "2022/0000000001") self.assertEqual(opening_invoice.entry_number, "2022/00000001")
self.assertEqual(old_invoice.entry_number, "2022/0000000002") self.assertEqual(old_invoice.entry_number, "2022/00000002")
self.assertEqual(new_invoice.entry_number, "2022/0000000003") self.assertEqual(new_invoice.entry_number, "2022/00000003")
self.assertEqual(next_year_invoice.entry_number, "2023/0000000001") self.assertEqual(next_year_invoice.entry_number, "2023/00000001")
@users("test_invoicer") @users("test_invoicer")
def test_install_no_entry_number(self): def test_install_no_entry_number(self):
@ -88,3 +100,21 @@ class RenumberCase(TestAccountReconciliationCommon):
invoice.action_post() invoice.action_post()
# Ensure there's no entry number # Ensure there's no entry number
self.assertFalse(invoice.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")

View File

@ -20,7 +20,11 @@
<field name="inherit_id" ref="account.view_account_journal_form" /> <field name="inherit_id" ref="account.view_account_journal_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="refund_sequence" position="before"> <field name="refund_sequence" position="before">
<field name="entry_number_sequence_id" /> <field name="entry_number_sequence_id_name" invisible="1" />
<field
name="entry_number_sequence_id"
attrs="{'readonly':[('entry_number_sequence_id_name','=','account_journal_general_sequence.default')]}"
/>
</field> </field>
</field> </field>
</record> </record>

View File

@ -41,13 +41,21 @@ class AccountMoveRenumberWizard(models.TransientModel):
def _default_entry_number_sequence(self): def _default_entry_number_sequence(self):
"""Get default sequence if it exists.""" """Get default sequence if it exists."""
return self.env["ir.sequence"].search( 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 @api.model
def _default_available_sequence_ids(self): def _default_available_sequence_ids(self):
"""Let view display only journal-related sequences.""" """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): def action_renumber(self):
"""Renumber moves. """Renumber moves.