2
0

sequence is now required on journals

Add post-install script to create a sequence for all existing journals
Update README accordingly
This commit is contained in:
Alexis de Lattre 2021-09-08 14:21:43 +02:00 committed by Rodrigo
parent 42def7f06f
commit 4aeaa9ca51
9 changed files with 118 additions and 39 deletions

View File

@ -1 +1,2 @@
from .post_install import create_journal_sequences
from . import models

View File

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

View File

@ -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.",

View File

@ -2,31 +2,44 @@
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# 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

View File

@ -0,0 +1,25 @@
# Copyright 2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# 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

View File

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

View File

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

View File

@ -6,29 +6,25 @@
-->
<odoo>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="model">account.journal</field>
<field
name="inherit_id"
ref="account.view_account_journal_form"
/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field
<record id="view_account_journal_form" model="ir.ui.view">
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form" />
<field name="arch" type="xml">
<field name="refund_sequence" position="before">
<field
name="sequence_id"
required="0"
context="{'default_name': name, 'default_company_id': company_id, 'default_implementation': 'no_gap', 'default_padding': 4, 'default_use_date_range': True, 'default_prefix': code + '/%%(range_year)s/'}"
/>
<field
name="refund_sequence"
attrs="{'invisible': [('type', 'not in', ('sale', 'purchase'))]}"
/>
<field
</field>
<field name="refund_sequence" position="after">
<field
name="refund_sequence_id"
attrs="{'invisible': ['|', ('type', 'not in', ('sale', 'purchase')), ('refund_sequence', '=', False)]}"
context="{'default_name': name, 'default_company_id': company_id, 'default_implementation': 'no_gap', 'default_padding': 4, 'default_use_date_range': True, 'default_prefix': 'R' + code + '/%%(range_year)s/'}"
/>
</field>
</field>
</record>
</field>
</field>
</record>
</odoo>
</odoo>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_move_form" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath
expr="//div[hasclass('oe_title')]/h1[hasclass('mt0')]"
position="attributes"
>
<attribute
name="attrs"
>{'invisible': [('name', '=', '/')]}</attribute>
</xpath>
<xpath
expr="//div[hasclass('oe_title')]//field[@name='name']"
position="attributes"
>
<attribute name="attrs">{'readonly': 1}</attribute>
</xpath>
<xpath expr="//field[@name='highest_name']/.." position="attributes">
<attribute name="attrs">{'invisible': 1}</attribute>
</xpath>
</field>
</record>
</odoo>