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:
parent
42def7f06f
commit
4aeaa9ca51
@ -1 +1,2 @@
|
||||
from .post_install import create_journal_sequences
|
||||
from . import models
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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.",
|
||||
|
@ -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
|
||||
|
25
account_move_name_sequence/post_install.py
Normal file
25
account_move_name_sequence/post_install.py
Normal 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
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
33
account_move_name_sequence/views/account_move.xml
Normal file
33
account_move_name_sequence/views/account_move.xml
Normal 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>
|
Loading…
Reference in New Issue
Block a user