diff --git a/account_auto_fy_sequence/__init__.py b/account_auto_fy_sequence/__init__.py new file mode 100644 index 000000000..1bc695ede --- /dev/null +++ b/account_auto_fy_sequence/__init__.py @@ -0,0 +1,26 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## + +from . import models diff --git a/account_auto_fy_sequence/__openerp__.py b/account_auto_fy_sequence/__openerp__.py new file mode 100644 index 000000000..de6ba5da3 --- /dev/null +++ b/account_auto_fy_sequence/__openerp__.py @@ -0,0 +1,56 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Automatic Fiscal Year Sequences', + 'version': '0.1', + 'category': 'Accounting', + 'description': """ + Automatic creation of fiscal year sequences. + + This module adds the possibility to use the %(fy)s placeholder + in sequences. %(fy)s is replaced by the fiscal year code when + using the sequence. + + The first time the sequence is used for a given fiscal year, + a specific fiscal year sequence starting at 1 is created automatically. + + /!\ If you change %(year)s to %(fy)s on a sequence that has + already been used for the current fiscal year, make sure to manually + create the fiscal year sequence for the current fiscal year and + initialize it's next number to the correct value. + For this reason, the module will forbid the user to change + a sequence from %(year)s to %(fy)s if it's next number is > 1. + """, + 'author': 'ACSONE SA/NV', + 'website': 'http://acsone.eu', + 'depends': ['account'], + 'data': [ + 'views/ir_sequence_view.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': False, + 'license': 'AGPL-3', +} diff --git a/account_auto_fy_sequence/i18n/account_auto_fy_sequence.pot b/account_auto_fy_sequence/i18n/account_auto_fy_sequence.pot new file mode 100644 index 000000000..47d80b514 --- /dev/null +++ b/account_auto_fy_sequence/i18n/account_auto_fy_sequence.pot @@ -0,0 +1,34 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_auto_fy_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-11-24 11:26+0000\n" +"PO-Revision-Date: 2014-11-24 11:26+0000\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_auto_fy_sequence +#: code:addons/account_auto_fy_sequence/models/ir_sequence.py:44 +#, python-format +msgid "Error!" +msgstr "" + +#. module: account_auto_fy_sequence +#: code:addons/account_auto_fy_sequence/models/ir_sequence.py:45 +#, python-format +msgid "The system tried to access a fiscal year sequence without specifying the actual fiscal year." +msgstr "" + +#. module: account_auto_fy_sequence +#: model:ir.model,name:account_auto_fy_sequence.model_ir_sequence +msgid "ir.sequence" +msgstr "" + diff --git a/account_auto_fy_sequence/i18n/fr.po b/account_auto_fy_sequence/i18n/fr.po new file mode 100644 index 000000000..b74bbe1ab --- /dev/null +++ b/account_auto_fy_sequence/i18n/fr.po @@ -0,0 +1,34 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_auto_fy_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-11-24 11:26+0000\n" +"PO-Revision-Date: 2014-11-24 11:26+0000\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_auto_fy_sequence +#: code:addons/account_auto_fy_sequence/models/ir_sequence.py:44 +#, python-format +msgid "Error!" +msgstr "Erreur!" + +#. module: account_auto_fy_sequence +#: code:addons/account_auto_fy_sequence/models/ir_sequence.py:45 +#, python-format +msgid "The system tried to access a fiscal year sequence without specifying the actual fiscal year." +msgstr "Le système tente d'accéder à une séquence pour exercice fiscal sans préciser d'exercice." + +#. module: account_auto_fy_sequence +#: model:ir.model,name:account_auto_fy_sequence.model_ir_sequence +msgid "ir.sequence" +msgstr "" + diff --git a/account_auto_fy_sequence/models/__init__.py b/account_auto_fy_sequence/models/__init__.py new file mode 100644 index 000000000..8833fa6e1 --- /dev/null +++ b/account_auto_fy_sequence/models/__init__.py @@ -0,0 +1,26 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## + +from . import ir_sequence diff --git a/account_auto_fy_sequence/models/ir_sequence.py b/account_auto_fy_sequence/models/ir_sequence.py new file mode 100644 index 000000000..855e1370e --- /dev/null +++ b/account_auto_fy_sequence/models/ir_sequence.py @@ -0,0 +1,126 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## + +from openerp.osv import orm +from openerp.tools.translate import _ + +FY_SLOT = '%(fy)s' +YEAR_SLOT = '%(year)s' + + +class Sequence(orm.Model): + _inherit = 'ir.sequence' + + def _create_fy_sequence(self, cr, uid, seq, fiscalyear, context=None): + """ Create a FY sequence by cloning a sequence + which has %(fy)s in prefix or suffix """ + fy_seq_id = self.create(cr, uid, { + 'name': seq.name + ' - ' + fiscalyear.code, + 'code': seq.code, + 'implementation': seq.implementation, + 'prefix': (seq.prefix and + seq.prefix.replace(FY_SLOT, fiscalyear.code)), + 'suffix': (seq.suffix and + seq.suffix.replace(FY_SLOT, fiscalyear.code)), + 'number_next': 1, + 'number_increment': seq.number_increment, + 'padding': seq.padding, + 'company_id': seq.company_id.id, + }, context=context) + self.pool['account.sequence.fiscalyear']\ + .create(cr, uid, { + 'sequence_id': fy_seq_id, + 'sequence_main_id': seq.id, + 'fiscalyear_id': fiscalyear.id, + }, context=context) + return fy_seq_id + + def _next(self, cr, uid, seq_ids, context=None): + if context is None: + context = {} + for seq in self.browse(cr, uid, seq_ids, context): + if (seq.prefix and FY_SLOT in seq.prefix) or \ + (seq.suffix and FY_SLOT in seq.suffix): + fiscalyear_id = context.get('fiscalyear_id') + if not fiscalyear_id: + raise orm.except_orm(_('Error!'), + _('The system tried to access ' + 'a fiscal year sequence ' + 'without specifying the actual ' + 'fiscal year.')) + # search for existing fiscal year sequence + # here we behave exactly like addons/account/ir_sequence.py + for line in seq.fiscal_ids: + if line.fiscalyear_id.id == fiscalyear_id: + return super(Sequence, self)\ + ._next(cr, uid, [line.sequence_id.id], context) + # no fiscal year sequence found, auto create it + if len(seq_ids) != 1: + # Where fiscal year sequences are used, we + # should always have one and only one sequence + # (which is the one associated to the journal). + # If this is not the case we'll need to investigate + # why, but we prefer to abort here instead of + # doing something potentially harmful. + raise orm.except_orm(_('Error!'), + _('The system tried to access ' + 'a fiscal year sequence ' + 'but there is more than one ' + 'sequence to choose from.')) + fiscalyear = self.pool['account.fiscalyear']\ + .browse(cr, uid, fiscalyear_id, context=context) + fy_seq_id = self\ + ._create_fy_sequence(cr, uid, seq, fiscalyear, context) + return super(Sequence, self)\ + ._next(cr, uid, [fy_seq_id], context) + return super(Sequence, self)._next(cr, uid, seq_ids, context) + + def write(self, cr, uid, ids, vals, context=None): + if isinstance(ids, (int, long)): + ids = [ids] + new_prefix = vals.get('prefix') + new_suffix = vals.get('suffix') + if (new_prefix and FY_SLOT in new_prefix) or \ + (new_suffix and FY_SLOT in new_suffix): + for seq in self.browse(cr, uid, ids, context=context): + if (seq.prefix and + YEAR_SLOT in seq.prefix and + new_prefix and + FY_SLOT in new_prefix) or \ + (seq.suffix and + YEAR_SLOT in seq.suffix and + new_suffix and + FY_SLOT in new_suffix): + if seq.number_next > 1 or vals.get('number_next', 1) > 1: + # we are converting from %(year)s to %(fy)s + # and the next number is > 1; this means the + # sequence has already been used. + raise orm.except_orm(_('Error!'), + _('You cannot change from ' + '%s to %s ' + 'for a sequence with ' + 'next number > 1' % + (YEAR_SLOT, FY_SLOT))) + return super(Sequence, self).write(cr, uid, ids, vals, context=context) diff --git a/account_auto_fy_sequence/tests/__init__.py b/account_auto_fy_sequence/tests/__init__.py new file mode 100644 index 000000000..a31764f72 --- /dev/null +++ b/account_auto_fy_sequence/tests/__init__.py @@ -0,0 +1,30 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## + +from . import test_auto_fy_sequence + +checks = [ + test_auto_fy_sequence, +] diff --git a/account_auto_fy_sequence/tests/test_auto_fy_sequence.py b/account_auto_fy_sequence/tests/test_auto_fy_sequence.py new file mode 100644 index 000000000..235822ca7 --- /dev/null +++ b/account_auto_fy_sequence/tests/test_auto_fy_sequence.py @@ -0,0 +1,69 @@ +# coding=utf-8 +############################################################################## +# +# account_auto_fy_sequence module for Odoo +# Copyright (C) 2014 ACSONE SA/NV () +# @author Stéphane Bidoul +# +# account_auto_fy_sequence is free software: +# you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License v3 or later +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# account_auto_fy_sequence is distributed +# in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License v3 or later for more details. +# +# You should have received a copy of the GNU Affero General Public License +# v3 or later along with this program. +# If not, see . +# +############################################################################## + +import time + +import openerp.tests.common as common +from openerp.osv import orm + + +class TestAutoFYSequence(common.TransactionCase): + + def setUp(self): + super(TestAutoFYSequence, self).setUp() + self.seq_obj = self.registry('ir.sequence') + + def _create_seq(self, prefix): + seq_id = self.seq_obj.create(self.cr, self.uid, { + 'name': 'test sequence', + 'implementation': 'no_gap', + 'prefix': prefix, + }) + return seq_id + + def test_0(self): + """ normal sequence """ + seq_id = self._create_seq('SEQ/%(year)s/') + n = self.seq_obj._next(self.cr, self.uid, [seq_id]) + self.assertEqual(n, "SEQ/%s/1" % time.strftime("%Y")) + + def test_1(self): + """ invoke fiscal year sequence + without specifying the fiscal year """ + seq_id = self._create_seq('SEQ/%(fy)s/') + with self.assertRaises(orm.except_orm): + self.seq_obj._next(self.cr, self.uid, [seq_id]) + + def test_2(self): + """ invoke fiscal year sequence """ + fiscalyear_id = self.ref('account.data_fiscalyear') + context = {'fiscalyear_id': fiscalyear_id} + fiscalyear = self.registry('account.fiscalyear')\ + .browse(self.cr, self.uid, fiscalyear_id) + seq_id = self._create_seq('SEQ/%(fy)s/') + n = self.seq_obj._next(self.cr, self.uid, [seq_id], context) + self.assertEqual(n, "SEQ/%s/1" % fiscalyear.code) + n = self.seq_obj._next(self.cr, self.uid, [seq_id], context) + self.assertEqual(n, "SEQ/%s/2" % fiscalyear.code) diff --git a/account_auto_fy_sequence/views/ir_sequence_view.xml b/account_auto_fy_sequence/views/ir_sequence_view.xml new file mode 100644 index 000000000..2a26e144b --- /dev/null +++ b/account_auto_fy_sequence/views/ir_sequence_view.xml @@ -0,0 +1,16 @@ + + + + + ir.sequence.form + ir.sequence + + + + + + +