From 6d6f22015a58df1c44368a7691ee24125acf7a6d Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 27 Sep 2011 20:38:30 +0200 Subject: [PATCH 01/14] [IMP] ir_sequence: whitespace and other hair cut changes. bzr revid: vmt@openerp.com-20110927183830-9mkkphmpzquyqsjn --- openerp/addons/base/ir/ir_sequence.py | 55 +++++++++++++++------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 4267e92d54d..0b805cc886f 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -20,49 +20,55 @@ ############################################################################## import time -from osv import fields,osv -import pooler -class ir_sequence_type(osv.osv): +import openerp + +class ir_sequence_type(openerp.osv.osv.osv): _name = 'ir.sequence.type' _order = 'name' _columns = { - 'name': fields.char('Name',size=64, required=True), - 'code': fields.char('Code',size=32, required=True), + 'name': openerp.osv.fields.char('Name', size=64, required=True), + 'code': openerp.osv.fields.char('Code', size=32, required=True), } -ir_sequence_type() def _code_get(self, cr, uid, context={}): cr.execute('select code, name from ir_sequence_type') return cr.fetchall() -class ir_sequence(osv.osv): +class ir_sequence(openerp.osv.osv.osv): + """ Sequence model. + + The sequence model allows to define and use so-called sequence objects. + Such objects are used to generate unique identifiers in a transaction-safe + way. + + """ _name = 'ir.sequence' _order = 'name' _columns = { - 'name': fields.char('Name',size=64, required=True), - 'code': fields.selection(_code_get, 'Code',size=64, required=True), - 'active': fields.boolean('Active'), - 'prefix': fields.char('Prefix',size=64, help="Prefix value of the record for the sequence"), - 'suffix': fields.char('Suffix',size=64, help="Suffix value of the record for the sequence"), - 'number_next': fields.integer('Next Number', required=True, help="Next number of this sequence"), - 'number_increment': fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"), - 'padding' : fields.integer('Number padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."), - 'company_id': fields.many2one('res.company', 'Company'), + 'name': openerp.osv.fields.char('Name', size=64, required=True), + 'code': openerp.osv.fields.selection(_code_get, 'Code',size=64, required=True), + 'active': openerp.osv.fields.boolean('Active'), + 'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"), + 'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"), + 'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"), + 'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"), + 'padding' : openerp.osv.fields.integer('Number padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."), + 'company_id': openerp.osv.fields.many2one('res.company', 'Company'), } _defaults = { - 'active': lambda *a: True, + 'active': True, 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.sequence', context=c), - 'number_increment': lambda *a: 1, - 'number_next': lambda *a: 1, - 'padding' : lambda *a : 0, + 'number_increment': 1, + 'number_next': 1, + 'padding' : 0, } def _process(self, s): return (s or '') % { - 'year':time.strftime('%Y'), + 'year': time.strftime('%Y'), 'month': time.strftime('%m'), - 'day':time.strftime('%d'), + 'day': time.strftime('%d'), 'y': time.strftime('%y'), 'doy': time.strftime('%j'), 'woy': time.strftime('%W'), @@ -93,9 +99,8 @@ class ir_sequence(osv.osv): return self._process(res['prefix']) + self._process(res['suffix']) return False - def get(self, cr, uid, code): - return self.get_id(cr, uid, code, test='code') -ir_sequence() + def get(self, cr, uid, code, context=None): + return self.get_id(cr, uid, code, 'code', context) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 0a8fe1e3b5696dc5bf7d46154cb7c0f3335691f5 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 27 Sep 2011 23:36:12 +0200 Subject: [PATCH 02/14] [IMP] ir_sequence: draining the swamp while being up to my neck in alligators. bzr revid: vmt@openerp.com-20110927213612-y8qzz2cma1cmfo69 --- openerp/addons/base/ir/ir_sequence.py | 94 +++++++++++++++++++-------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 0b805cc886f..90b3a5892b7 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -31,10 +31,17 @@ class ir_sequence_type(openerp.osv.osv.osv): 'code': openerp.osv.fields.char('Code', size=32, required=True), } + _sql_constraints = [ + ('code_unique', 'unique(code)', '`code` must be unique.'), + ] + def _code_get(self, cr, uid, context={}): cr.execute('select code, name from ir_sequence_type') return cr.fetchall() +IMPLEMENTATION_SELECTION = \ + [('standard', 'Standard'), ('no_gap', 'No gap')] + class ir_sequence(openerp.osv.osv.osv): """ Sequence model. @@ -47,7 +54,12 @@ class ir_sequence(openerp.osv.osv.osv): _order = 'name' _columns = { 'name': openerp.osv.fields.char('Name', size=64, required=True), - 'code': openerp.osv.fields.selection(_code_get, 'Code',size=64, required=True), + 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64, required=True), # TODO should it be unique? + 'implementation': openerp.osv.fields.selection( # TODO update the view + IMPLEMENTATION_SELECTION, 'Implementation', required=True, + help="Two sequence object implementations are offered: Standard " + "and 'No gap'. The later is slower than the former but forbids any" + " gap in the sequence (while they are possible in the former)."), 'active': openerp.osv.fields.boolean('Active'), 'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"), 'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"), @@ -57,6 +69,7 @@ class ir_sequence(openerp.osv.osv.osv): 'company_id': openerp.osv.fields.many2one('res.company', 'Company'), } _defaults = { + 'implementation': 'standard', 'active': True, 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.sequence', context=c), 'number_increment': 1, @@ -64,42 +77,69 @@ class ir_sequence(openerp.osv.osv.osv): 'padding' : 0, } - def _process(self, s): - return (s or '') % { - 'year': time.strftime('%Y'), - 'month': time.strftime('%m'), - 'day': time.strftime('%d'), - 'y': time.strftime('%y'), - 'doy': time.strftime('%j'), - 'woy': time.strftime('%W'), - 'weekday': time.strftime('%w'), - 'h24': time.strftime('%H'), - 'h12': time.strftime('%I'), - 'min': time.strftime('%M'), - 'sec': time.strftime('%S'), + def create(self, cr, uid, values, context=None): + values = self._add_missing_default_values(cr, uid, values, context) + go = super(ir_sequence, self).create \ + if values['implementation'] == 'standard' else self.create_nogap + return go(cr, uid, values, context) + + def _interpolate(self, s, d): + return s % d if s else '' + + def _interpolation_dict(self): + t = time.localtime() # Actually, the server is always in UTC. + return { + 'year': time.strftime('%Y', t), + 'month': time.strftime('%m', t), + 'day': time.strftime('%d', t), + 'y': time.strftime('%y', t), + 'doy': time.strftime('%j', t), + 'woy': time.strftime('%W', t), + 'weekday': time.strftime('%w', t), + 'h24': time.strftime('%H', t), + 'h12': time.strftime('%I', t), + 'min': time.strftime('%M', t), + 'sec': time.strftime('%S', t), } - def get_id(self, cr, uid, sequence_id, test='id', context=None): - assert test in ('code','id') + # TODO rename 'test' to 'code_or_id' in account/sequence. + def get_id(self, cr, uid, sequence_code_or_id, code_or_id='id', context=None): + """ Draw an interpolated string using the specified sequence. + + The sequence to use is specified by the ``sequence_code_or_id`` + argument, which can be a code or an id (as controlled by the + ``code_or_id`` argument. + """ + assert code_or_id in ('code', 'id') company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) - cr.execute('''SELECT id, number_next, prefix, suffix, padding - FROM ir_sequence - WHERE %s=%%s - AND active=true - AND (company_id in %%s or company_id is NULL) - ORDER BY company_id, id - FOR UPDATE NOWAIT''' % test, - (sequence_id, tuple(company_ids))) + cr.execute(''' + SELECT id, number_next, prefix, suffix, padding + FROM ir_sequence + WHERE %s=%%s + AND active=true + AND (company_id in %%s or company_id is NULL) + ORDER BY company_id, id + LIMIT 1 + FOR UPDATE NOWAIT''' % code_or_id, + (sequence_code_or_id, tuple(company_ids))) res = cr.dictfetchone() if res: - cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=true', (res['id'],)) + d = self._interpolation_dict() + interpolated_prefix = self._interpolate(res['prefix'], d) + interpolated_suffix = self._interpolate(res['suffix'], d) + cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s', (res['id'],)) if res['number_next']: - return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) + return interpolated_prefix + '%%0%sd' % res['padding'] % res['number_next'] + interpolated_suffix else: - return self._process(res['prefix']) + self._process(res['suffix']) + # TODO what is this case used for ? + return interpolated_prefix + interpolated_suffix return False def get(self, cr, uid, code, context=None): + """ Draw an interpolated string using the specified sequence. + + The sequence to use is specified by its code. + """ return self.get_id(cr, uid, code, 'code', context) From 5f4ebc7b1c72fe8eb5dcd947761d8d8f03cd8891 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 11:13:09 +0200 Subject: [PATCH 03/14] [IMP] ir_sequence: add support for PostgreSQL sequence. This is partly inspired by openlabs' Sequence Postgres module. Untested yet. bzr revid: vmt@openerp.com-20110928091309-098red2biba5uq73 --- openerp/addons/base/ir/ir_sequence.py | 152 +++++++++++++++++++++----- 1 file changed, 126 insertions(+), 26 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 90b3a5892b7..3ff5009b567 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -79,10 +79,51 @@ class ir_sequence(openerp.osv.osv.osv): def create(self, cr, uid, values, context=None): values = self._add_missing_default_values(cr, uid, values, context) - go = super(ir_sequence, self).create \ - if values['implementation'] == 'standard' else self.create_nogap + go = super(ir_sequence, self).create_postgres \ + if values['implementation'] == 'standard' else self.create return go(cr, uid, values, context) + def create_postgres(self, cr, uid, values, context=None): + """ Create a fast, gaps-allowed PostgreSQL sequence. + + :param values: same argument than for ``create()`` but the keys + ``number_increment`` and ``number_next`` must be present. + ``_add_missing_default_values()`` can be used to this effect. + :return: id of the newly created record + """ + id = super(ir_sequence, self).create(cr, uid, values, context) + self._create_sequence(cr, + values['number_increment'], values['number_next']) + return id + + def unlink(self, cr, uid, ids, context=None): + super(ir_sequence, self).unlink(cr, uid, ids, context) + self._drop_sequence(cr, ids) + + def write(self, cr, uid, ids, values, context=None): + ids = ids if isinstance(ids, (list, tuple)) else [ids] + new_implementation = values.get('implementation') + rows = self.read(cr, uid, ids, ['id,' 'implementation', + 'number_increment', 'number_next'], context) + super(ir_sequence, self).write(cr, uid, ids, values, context) + + for row in rows: + # 4 cases: we test the previous impl. against the new one. + if row['implementation'] == 'standard': + i = values.get('number_increment', row['number_increment']) + n = values.get('number_next', row['number_next']) + if new_implementation in ('standard', None): + self._alter_sequence(cr, row['id'], i, n) + else: + self._drop_sequence(cr, row['id']) + else: + if new_implementation in ('no_gap', None): + pass + else: + self._create_sequence(cr, row['id'], i, n) + + return True + def _interpolate(self, s, d): return s % d if s else '' @@ -110,30 +151,34 @@ class ir_sequence(openerp.osv.osv.osv): argument, which can be a code or an id (as controlled by the ``code_or_id`` argument. """ - assert code_or_id in ('code', 'id') - company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) - cr.execute(''' - SELECT id, number_next, prefix, suffix, padding - FROM ir_sequence - WHERE %s=%%s - AND active=true - AND (company_id in %%s or company_id is NULL) - ORDER BY company_id, id - LIMIT 1 - FOR UPDATE NOWAIT''' % code_or_id, - (sequence_code_or_id, tuple(company_ids))) - res = cr.dictfetchone() - if res: - d = self._interpolation_dict() - interpolated_prefix = self._interpolate(res['prefix'], d) - interpolated_suffix = self._interpolate(res['suffix'], d) - cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s', (res['id'],)) - if res['number_next']: - return interpolated_prefix + '%%0%sd' % res['padding'] % res['number_next'] + interpolated_suffix - else: - # TODO what is this case used for ? - return interpolated_prefix + interpolated_suffix - return False + # TODO there is no access rights check on the sequence itself. + res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, + code_or_id, context) + + if not res: + return False + + if res['implementation'] == 'standard': + cr.execute(""" + SELECT nextval('ir_sequence_%03d') + """, (res['id'],)) + res['number_next'] = cr.fetchone() + else: + cr.execute(""" + UPDATE ir_sequence + SET number_next=number_next+number_increment + WHERE id=%s + """, (res['id'],)) + + d = self._interpolation_dict() + interpolated_prefix = self._interpolate(res['prefix'], d) + interpolated_suffix = self._interpolate(res['suffix'], d) + if res['number_next']: + return interpolated_prefix + '%%0%sd' % res['padding'] % \ + res['number_next'] + interpolated_suffix + else: + # TODO what is this case used for ? + return interpolated_prefix + interpolated_suffix def get(self, cr, uid, code, context=None): """ Draw an interpolated string using the specified sequence. @@ -142,5 +187,60 @@ class ir_sequence(openerp.osv.osv.osv): """ return self.get_id(cr, uid, code, 'code', context) + def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, context=None): + """ Read a sequence object. + + There is no access rights check on the sequence itself. + """ + assert code_or_id in ('code', 'id') + res_company = self.pool.get('res.company') + company_ids = res_company.search(cr, uid, [], context=context) + cr.execute(""" + SELECT id, number_next, prefix, suffix, padding, implementation + FROM ir_sequence + WHERE %s=%%s + AND active=true + AND (company_id in %%s or company_id is NULL) + ORDER BY company_id, id + LIMIT 1 + FOR UPDATE NOWAIT + """ % code_or_id, (sequence_code_or_id, tuple(company_ids))) + return cr.dictfetchone() + + def _create_sequence(self, cr, number_increment, number_next): + """ Create a PostreSQL sequence. + + There is no access rights check. + """ + cr.execute(""" + CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %s START WITH %s + """, (id, number_increment, number_next)) + + def _drop_sequence(self, cr, ids): + """ Drop the PostreSQL sequence if it exists. + + There is no access rights check. + """ + + ids = ids if isinstance(ids, (list, tuple)) else [ids] + assert all(isinstance(i, (int, long)) for i in ids), \ + "Only ids in (int, long) allowed." + names = ','.join('ir_sequence_%03d' % i for i in ids) + + # RESTRICT is the default; it prevents dropping the sequence if an + # object depends on it. + cr.execute(""" + DROP SEQUENCE IF EXISTS %s RESTRICT + """ % names) + + def _alter_sequence(self, cr, id, number_increment, number_next): + """ Alter a PostreSQL sequence. + + There is no access rights check. + """ + cr.execute(""" + ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %s RESTART WITH %s + """, (id, number_increment, number_next)) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From f2c5556b68f6879766dadf6522e35f4afc16696e Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 12:30:09 +0200 Subject: [PATCH 04/14] [FIX] ir_sequence: forgot id argument in _create_sequence(). bzr revid: vmt@openerp.com-20110928103009-17rw1af5ebauu3f5 --- openerp/addons/base/ir/ir_sequence.py | 22 ++++++----- tests/common.py | 47 ++++++++++++++++++++++ tests/test_ir_sequence.py | 57 +++++++++++++++++++++++++++ tests/test_xmlrpc.py | 54 ++++++------------------- 4 files changed, 129 insertions(+), 51 deletions(-) create mode 100644 tests/common.py create mode 100644 tests/test_ir_sequence.py diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 3ff5009b567..086d48ac44d 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -54,7 +54,7 @@ class ir_sequence(openerp.osv.osv.osv): _order = 'name' _columns = { 'name': openerp.osv.fields.char('Name', size=64, required=True), - 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64, required=True), # TODO should it be unique? + 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64, required=True), 'implementation': openerp.osv.fields.selection( # TODO update the view IMPLEMENTATION_SELECTION, 'Implementation', required=True, help="Two sequence object implementations are offered: Standard " @@ -79,8 +79,8 @@ class ir_sequence(openerp.osv.osv.osv): def create(self, cr, uid, values, context=None): values = self._add_missing_default_values(cr, uid, values, context) - go = super(ir_sequence, self).create_postgres \ - if values['implementation'] == 'standard' else self.create + go = super(ir_sequence, self).create \ + if values['implementation'] == 'no_gap' else self.create_postgres return go(cr, uid, values, context) def create_postgres(self, cr, uid, values, context=None): @@ -92,7 +92,7 @@ class ir_sequence(openerp.osv.osv.osv): :return: id of the newly created record """ id = super(ir_sequence, self).create(cr, uid, values, context) - self._create_sequence(cr, + self._create_sequence(cr, id, values['number_increment'], values['number_next']) return id @@ -161,7 +161,7 @@ class ir_sequence(openerp.osv.osv.osv): if res['implementation'] == 'standard': cr.execute(""" SELECT nextval('ir_sequence_%03d') - """, (res['id'],)) + """ % res['id']) res['number_next'] = cr.fetchone() else: cr.execute(""" @@ -207,14 +207,15 @@ class ir_sequence(openerp.osv.osv.osv): """ % code_or_id, (sequence_code_or_id, tuple(company_ids))) return cr.dictfetchone() - def _create_sequence(self, cr, number_increment, number_next): + def _create_sequence(self, cr, id, number_increment, number_next): """ Create a PostreSQL sequence. There is no access rights check. """ + assert isinstance(id, (int, long)) cr.execute(""" - CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %s START WITH %s - """, (id, number_increment, number_next)) + CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s + """ % id, (number_increment, number_next)) def _drop_sequence(self, cr, ids): """ Drop the PostreSQL sequence if it exists. @@ -238,9 +239,10 @@ class ir_sequence(openerp.osv.osv.osv): There is no access rights check. """ + assert isinstance(id, (int, long)) cr.execute(""" - ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %s RESTART WITH %s - """, (id, number_increment, number_next)) + ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s + """ % id, (number_increment, number_next)) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/tests/common.py b/tests/common.py new file mode 100644 index 00000000000..eb34772d1af --- /dev/null +++ b/tests/common.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +import os +import time +import unittest2 +import xmlrpclib + +import openerp + +ADDONS_PATH = os.environ['OPENERP_ADDONS_PATH'] +PORT = int(os.environ['OPENERP_PORT']) +DB = os.environ['OPENERP_DATABASE'] + +HOST = '127.0.0.1' + +ADMIN_USER = 'admin' +ADMIN_USER_ID = 1 +ADMIN_PASSWORD = 'admin' + +common_proxy_60 = None +db_proxy_60 = None +object_proxy_60 = None + +def setUpModule(): + """ + Start the OpenERP server similary to the openerp-server script and + setup some xmlrpclib proxies. + """ + openerp.tools.config['addons_path'] = ADDONS_PATH + openerp.tools.config['xmlrpc_port'] = PORT + openerp.service.start_services() + + global common_proxy_60 + global db_proxy_60 + global object_proxy_60 + + # Use the old (pre 6.1) API. + url = 'http://%s:%d/xmlrpc/' % (HOST, PORT) + common_proxy_60 = xmlrpclib.ServerProxy(url + 'common') + db_proxy_60 = xmlrpclib.ServerProxy(url + 'db') + object_proxy_60 = xmlrpclib.ServerProxy(url + 'object') + + # Ugly way to ensure the server is listening. + time.sleep(2) + +def tearDownModule(): + """ Shutdown the OpenERP server similarly to a single ctrl-c. """ + openerp.service.stop_services() diff --git a/tests/test_ir_sequence.py b/tests/test_ir_sequence.py new file mode 100644 index 00000000000..ef7e6784daa --- /dev/null +++ b/tests/test_ir_sequence.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# Run with one of these commands: +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_ir_sequence.py +# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy nosetests tests/test_ir_sequence.py +# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ +# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence +import os +import time +import unittest2 +import xmlrpclib + +import openerp +import common + +DB = common.DB +ADMIN_USER_ID = common.ADMIN_USER_ID + +setUpModule = common.setUpModule +tearDownModule = common.tearDownModule + +def registry(model): + return openerp.modules.registry.RegistryManager.get(DB)[model] + +def cursor(): + return openerp.modules.registry.RegistryManager.get(DB).db.cursor() + +class test_ir_sequence(unittest2.TestCase): + + def test_ir_sequence_create(self): + """ Try to create a sequence object. """ + cr = cursor() + try: + d = dict(code='test_sequence_type', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type', name='Test sequence') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + finally: + cr.close() + + def test_ir_sequence_search(self): + """ Try a search. """ + cr = cursor() + try: + ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, [], {}) + assert ids + cr.commit() + finally: + cr.close() + +if __name__ == '__main__': + unittest2.main() + diff --git a/tests/test_xmlrpc.py b/tests/test_xmlrpc.py index 30af863f12d..35ba07b940a 100644 --- a/tests/test_xmlrpc.py +++ b/tests/test_xmlrpc.py @@ -12,43 +12,15 @@ import unittest2 import xmlrpclib import openerp +import common -ADDONS_PATH = os.environ['OPENERP_ADDONS_PATH'] -PORT = int(os.environ['OPENERP_PORT']) -DB = os.environ['OPENERP_DATABASE'] +DB = common.DB +ADMIN_USER = common.ADMIN_USER +ADMIN_USER_ID = common.ADMIN_USER_ID +ADMIN_PASSWORD = common.ADMIN_PASSWORD -HOST = '127.0.0.1' - -ADMIN_USER = 'admin' -ADMIN_USER_ID = 1 -ADMIN_PASSWORD = 'admin' - -common_proxy_60 = None -db_proxy_60 = None -object_proxy_60 = None - -def setUpModule(): - """ - Start the OpenERP server similary to the openerp-server script and - setup some xmlrpclib proxies. - """ - openerp.tools.config['addons_path'] = ADDONS_PATH - openerp.tools.config['xmlrpc_port'] = PORT - openerp.service.start_services() - - global common_proxy_60 - global db_proxy_60 - global object_proxy_60 - - # Use the old (pre 6.1) API. - url = 'http://%s:%d/xmlrpc/' % (HOST, PORT) - common_proxy_60 = xmlrpclib.ServerProxy(url + 'common') - db_proxy_60 = xmlrpclib.ServerProxy(url + 'db') - object_proxy_60 = xmlrpclib.ServerProxy(url + 'object') - -def tearDownModule(): - """ Shutdown the OpenERP server similarly to a single ctrl-c. """ - openerp.service.stop_services() +setUpModule = common.setUpModule +tearDownModule = common.tearDownModule class test_xmlrpc(unittest2.TestCase): @@ -57,26 +29,26 @@ class test_xmlrpc(unittest2.TestCase): Simulate a OpenERP client requesting the creation of a database and polling the server until the creation is complete. """ - progress_id = db_proxy_60.create(ADMIN_PASSWORD, DB, True, False, - ADMIN_PASSWORD) + progress_id = common.db_proxy_60.create(ADMIN_PASSWORD, DB, True, + False, ADMIN_PASSWORD) while True: time.sleep(1) - progress, users = db_proxy_60.get_progress(ADMIN_PASSWORD, + progress, users = common.db_proxy_60.get_progress(ADMIN_PASSWORD, progress_id) if progress == 1.0: break def test_xmlrpc_login(self): """ Try to login on the common service. """ - uid = common_proxy_60.login(DB, ADMIN_USER, ADMIN_PASSWORD) + uid = common.common_proxy_60.login(DB, ADMIN_USER, ADMIN_PASSWORD) assert uid == ADMIN_USER_ID def test_xmlrpc_ir_model_search(self): """ Try a search on the object service. """ - ids = object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, + ids = common.object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', []) assert ids - ids = object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, + ids = common.object_proxy_60.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {}) assert ids From eeaa2a7f8073153e5bb838ff5ace51215d18d68a Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 13:42:29 +0200 Subject: [PATCH 05/14] [FIX] ir_sequence: do the FOR UPDATE NO WAIT only in the No-gap sequence. bzr revid: vmt@openerp.com-20110928114229-1g6r5et5frj26wam --- openerp/addons/base/ir/ir_sequence.py | 14 +++-- tests/test_ir_sequence.py | 74 ++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 086d48ac44d..c4d1a6f988b 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -153,7 +153,7 @@ class ir_sequence(openerp.osv.osv.osv): """ # TODO there is no access rights check on the sequence itself. res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, - code_or_id, context) + code_or_id, False, context) if not res: return False @@ -164,6 +164,9 @@ class ir_sequence(openerp.osv.osv.osv): """ % res['id']) res['number_next'] = cr.fetchone() else: + # Read again with FOR UPDATE NO WAIT. + res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, + code_or_id, True, context) cr.execute(""" UPDATE ir_sequence SET number_next=number_next+number_increment @@ -187,7 +190,8 @@ class ir_sequence(openerp.osv.osv.osv): """ return self.get_id(cr, uid, code, 'code', context) - def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, context=None): + def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, + for_update_no_wait, context=None): """ Read a sequence object. There is no access rights check on the sequence itself. @@ -195,6 +199,7 @@ class ir_sequence(openerp.osv.osv.osv): assert code_or_id in ('code', 'id') res_company = self.pool.get('res.company') company_ids = res_company.search(cr, uid, [], context=context) + funw = 'FOR UPDATE NOWAIT' if for_update_no_wait else '' cr.execute(""" SELECT id, number_next, prefix, suffix, padding, implementation FROM ir_sequence @@ -203,8 +208,9 @@ class ir_sequence(openerp.osv.osv.osv): AND (company_id in %%s or company_id is NULL) ORDER BY company_id, id LIMIT 1 - FOR UPDATE NOWAIT - """ % code_or_id, (sequence_code_or_id, tuple(company_ids))) + %s + """ % (code_or_id, funw), + (sequence_code_or_id, tuple(company_ids))) return cr.dictfetchone() def _create_sequence(self, cr, id, number_increment, number_next): diff --git a/tests/test_ir_sequence.py b/tests/test_ir_sequence.py index ef7e6784daa..0fc7aec5b50 100644 --- a/tests/test_ir_sequence.py +++ b/tests/test_ir_sequence.py @@ -7,6 +7,7 @@ # > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ # OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence import os +import psycopg2 import time import unittest2 import xmlrpclib @@ -26,7 +27,8 @@ def registry(model): def cursor(): return openerp.modules.registry.RegistryManager.get(DB).db.cursor() -class test_ir_sequence(unittest2.TestCase): +class test_ir_sequence_standard(unittest2.TestCase): + """ A few tests for a 'Standard' (i.e. PostgreSQL) sequence. """ def test_ir_sequence_create(self): """ Try to create a sequence object. """ @@ -52,6 +54,76 @@ class test_ir_sequence(unittest2.TestCase): finally: cr.close() + def test_ir_sequence_draw(self): + """ Try to draw a number. """ + cr = cursor() + try: + n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n + cr.commit() + finally: + cr.close() + + def test_ir_sequence_draw_twice(self): + """ Try to draw a number from two transactions. """ + cr0 = cursor() + cr1 = cursor() + try: + n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n0 + n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n1 + cr0.commit() + cr1.commit() + finally: + cr0.close() + cr1.close() + +class test_ir_sequence_no_gap(unittest2.TestCase): + """ Copy of the previous tests for a 'No gap' sequence. """ + + def test_ir_sequence_create_no_gap(self): + """ Try to create a sequence object. """ + cr = cursor() + try: + d = dict(code='test_sequence_type_2', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_2', name='Test sequence', + implementation='no_gap') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + finally: + cr.close() + + def test_ir_sequence_draw_no_gap(self): + """ Try to draw a number. """ + cr = cursor() + try: + n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type_2', {}) + assert n + cr.commit() + finally: + cr.close() + + def test_ir_sequence_draw_twice_no_gap(self): + """ Try to draw a number from two transactions. + This is expected to not work. + """ + cr0 = cursor() + cr1 = cursor() + try: + msg_re = '^could not obtain lock on row in relation "ir_sequence"$' + with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re): + n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) + assert n0 + n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) + finally: + cr0.close() + cr1.close() + + if __name__ == '__main__': unittest2.main() From 7ac3c9077435a1e7c25328891600e4b203dc4731 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 15:05:48 +0200 Subject: [PATCH 06/14] [FIX] ir_sequence: check access right on get_id(), unlink returns True. bzr revid: vmt@openerp.com-20110928130548-ldg97pjo5zex0qab --- openerp/addons/base/ir/ir_sequence.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index c4d1a6f988b..4d10eefe75e 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -99,6 +99,7 @@ class ir_sequence(openerp.osv.osv.osv): def unlink(self, cr, uid, ids, context=None): super(ir_sequence, self).unlink(cr, uid, ids, context) self._drop_sequence(cr, ids) + return True def write(self, cr, uid, ids, values, context=None): ids = ids if isinstance(ids, (list, tuple)) else [ids] @@ -151,7 +152,7 @@ class ir_sequence(openerp.osv.osv.osv): argument, which can be a code or an id (as controlled by the ``code_or_id`` argument. """ - # TODO there is no access rights check on the sequence itself. + self.check_read(cr, uid) res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, code_or_id, False, context) From 42fe3d4ff5594afa16f34e926fb0a8ee40dc771c Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 15:27:44 +0200 Subject: [PATCH 07/14] [IMP] ir_sequence: added the new "implementation" field in the views. bzr revid: vmt@openerp.com-20110928132744-lb8m15yzg7kc3e56 --- openerp/addons/base/ir/ir.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 2792259773d..79490542b1c 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -176,6 +176,7 @@ + @@ -215,6 +216,7 @@ + From 6929d9f3c85d7623c86487e030c8464bb0d6c530 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 15:31:01 +0200 Subject: [PATCH 08/14] [FIX] ir_sequence: any merge proposal should touch as many .po files as possible. bzr revid: vmt@openerp.com-20110928133101-z1baqrqw7yb2u73c --- openerp/addons/base/i18n/af.po | 2 +- openerp/addons/base/i18n/am.po | 2 +- openerp/addons/base/i18n/ar.po | 2 +- openerp/addons/base/i18n/base.pot | 2 +- openerp/addons/base/i18n/bg.po | 2 +- openerp/addons/base/i18n/bs.po | 2 +- openerp/addons/base/i18n/ca.po | 2 +- openerp/addons/base/i18n/cs.po | 2 +- openerp/addons/base/i18n/da.po | 2 +- openerp/addons/base/i18n/de.po | 2 +- openerp/addons/base/i18n/el.po | 2 +- openerp/addons/base/i18n/en_GB.po | 4 ++-- openerp/addons/base/i18n/es.po | 2 +- openerp/addons/base/i18n/es_AR.po | 2 +- openerp/addons/base/i18n/es_CL.po | 2 +- openerp/addons/base/i18n/es_EC.po | 2 +- openerp/addons/base/i18n/et.po | 2 +- openerp/addons/base/i18n/eu.po | 2 +- openerp/addons/base/i18n/fa.po | 2 +- openerp/addons/base/i18n/fa_AF.po | 2 +- openerp/addons/base/i18n/fi.po | 2 +- openerp/addons/base/i18n/fr.po | 2 +- openerp/addons/base/i18n/gl.po | 2 +- openerp/addons/base/i18n/he.po | 2 +- openerp/addons/base/i18n/hr.po | 2 +- openerp/addons/base/i18n/hu.po | 4 ++-- openerp/addons/base/i18n/hy.po | 2 +- openerp/addons/base/i18n/id.po | 2 +- openerp/addons/base/i18n/is.po | 2 +- openerp/addons/base/i18n/it.po | 2 +- openerp/addons/base/i18n/ja.po | 2 +- openerp/addons/base/i18n/kk.po | 2 +- openerp/addons/base/i18n/ko.po | 2 +- openerp/addons/base/i18n/lt.po | 2 +- openerp/addons/base/i18n/lt_LT.po | 2 +- openerp/addons/base/i18n/lv.po | 2 +- openerp/addons/base/i18n/mk.po | 2 +- openerp/addons/base/i18n/mn.po | 2 +- openerp/addons/base/i18n/nb.po | 2 +- openerp/addons/base/i18n/nl.po | 2 +- openerp/addons/base/i18n/nl_BE.po | 2 +- openerp/addons/base/i18n/nl_NL.po | 2 +- openerp/addons/base/i18n/pl.po | 2 +- openerp/addons/base/i18n/pt.po | 2 +- openerp/addons/base/i18n/pt_BR.po | 2 +- openerp/addons/base/i18n/ro.po | 2 +- openerp/addons/base/i18n/ru.po | 2 +- openerp/addons/base/i18n/sk.po | 2 +- openerp/addons/base/i18n/sl.po | 2 +- openerp/addons/base/i18n/sq.po | 2 +- openerp/addons/base/i18n/sr.po | 2 +- openerp/addons/base/i18n/sr@latin.po | 2 +- openerp/addons/base/i18n/sv.po | 2 +- openerp/addons/base/i18n/th.po | 2 +- openerp/addons/base/i18n/tlh.po | 2 +- openerp/addons/base/i18n/tr.po | 2 +- openerp/addons/base/i18n/uk.po | 2 +- openerp/addons/base/i18n/uk_UA.po | 2 +- openerp/addons/base/i18n/ur.po | 2 +- openerp/addons/base/i18n/vi.po | 2 +- openerp/addons/base/i18n/zh_CN.po | 2 +- openerp/addons/base/i18n/zh_HK.po | 2 +- openerp/addons/base/i18n/zh_TW.po | 2 +- openerp/addons/base/ir/ir_sequence.py | 2 +- 64 files changed, 66 insertions(+), 66 deletions(-) diff --git a/openerp/addons/base/i18n/af.po b/openerp/addons/base/i18n/af.po index 72547d34bc1..87150c74641 100644 --- a/openerp/addons/base/i18n/af.po +++ b/openerp/addons/base/i18n/af.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/am.po b/openerp/addons/base/i18n/am.po index 7fa923c0660..31d0553c768 100644 --- a/openerp/addons/base/i18n/am.po +++ b/openerp/addons/base/i18n/am.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po index b50c02ca98d..afe9a26e63a 100644 --- a/openerp/addons/base/i18n/ar.po +++ b/openerp/addons/base/i18n/ar.po @@ -5430,7 +5430,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index 9484a376151..55c648f89af 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -5217,7 +5217,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/bg.po b/openerp/addons/base/i18n/bg.po index 02da984c8b3..bb9f54a129d 100644 --- a/openerp/addons/base/i18n/bg.po +++ b/openerp/addons/base/i18n/bg.po @@ -5572,7 +5572,7 @@ msgstr "Преводи" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Брой на остъпката" #. module: base diff --git a/openerp/addons/base/i18n/bs.po b/openerp/addons/base/i18n/bs.po index 80691631cf8..1cd99f744ad 100644 --- a/openerp/addons/base/i18n/bs.po +++ b/openerp/addons/base/i18n/bs.po @@ -5439,7 +5439,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ca.po b/openerp/addons/base/i18n/ca.po index 58c927285eb..6e9d7d6a6e7 100644 --- a/openerp/addons/base/i18n/ca.po +++ b/openerp/addons/base/i18n/ca.po @@ -5709,7 +5709,7 @@ msgstr "Traduccions" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Omplenat del número" #. module: base diff --git a/openerp/addons/base/i18n/cs.po b/openerp/addons/base/i18n/cs.po index 1a20a156fe9..e356d0b0973 100644 --- a/openerp/addons/base/i18n/cs.po +++ b/openerp/addons/base/i18n/cs.po @@ -5529,7 +5529,7 @@ msgstr "Překlady" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Zarovnání čísla" #. module: base diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po index 2fa355ab21a..2968a29195b 100644 --- a/openerp/addons/base/i18n/da.po +++ b/openerp/addons/base/i18n/da.po @@ -5431,7 +5431,7 @@ msgstr "Oversættelser" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/de.po b/openerp/addons/base/i18n/de.po index 4dbe8f4c0cf..c2fe1af3b93 100644 --- a/openerp/addons/base/i18n/de.po +++ b/openerp/addons/base/i18n/de.po @@ -5702,7 +5702,7 @@ msgstr "Übersetzungen" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Stellenanzahl" #. module: base diff --git a/openerp/addons/base/i18n/el.po b/openerp/addons/base/i18n/el.po index 4bca6580496..9e5cc4245c9 100644 --- a/openerp/addons/base/i18n/el.po +++ b/openerp/addons/base/i18n/el.po @@ -5614,7 +5614,7 @@ msgstr "Μεταφράσεις" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Συμπλήρωση αριθμών" #. module: base diff --git a/openerp/addons/base/i18n/en_GB.po b/openerp/addons/base/i18n/en_GB.po index 45a31676521..d013bbc9be6 100644 --- a/openerp/addons/base/i18n/en_GB.po +++ b/openerp/addons/base/i18n/en_GB.po @@ -5669,8 +5669,8 @@ msgstr "Translations" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" -msgstr "Number padding" +msgid "Number Padding" +msgstr "Number Padding" #. module: base #: view:ir.actions.report.xml:0 diff --git a/openerp/addons/base/i18n/es.po b/openerp/addons/base/i18n/es.po index 75c938bb99f..b21773bb137 100644 --- a/openerp/addons/base/i18n/es.po +++ b/openerp/addons/base/i18n/es.po @@ -5723,7 +5723,7 @@ msgstr "Traducciones" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Relleno del número" #. module: base diff --git a/openerp/addons/base/i18n/es_AR.po b/openerp/addons/base/i18n/es_AR.po index f22db5e97a5..3eac408dd86 100644 --- a/openerp/addons/base/i18n/es_AR.po +++ b/openerp/addons/base/i18n/es_AR.po @@ -4778,7 +4778,7 @@ msgstr "Traducciones" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Relleno del número" #. module: base diff --git a/openerp/addons/base/i18n/es_CL.po b/openerp/addons/base/i18n/es_CL.po index 6a7b66979ae..6e1328dd1d4 100644 --- a/openerp/addons/base/i18n/es_CL.po +++ b/openerp/addons/base/i18n/es_CL.po @@ -5725,7 +5725,7 @@ msgstr "Traducciones" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Relleno del número" #. module: base diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po index 172217838e6..62371e70beb 100644 --- a/openerp/addons/base/i18n/es_EC.po +++ b/openerp/addons/base/i18n/es_EC.po @@ -5712,7 +5712,7 @@ msgstr "Traducciones" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Relleno del número" #. module: base diff --git a/openerp/addons/base/i18n/et.po b/openerp/addons/base/i18n/et.po index 6062726cdc9..f5efbb2f667 100644 --- a/openerp/addons/base/i18n/et.po +++ b/openerp/addons/base/i18n/et.po @@ -5488,7 +5488,7 @@ msgstr "Tõlked" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Arvu täidistus" #. module: base diff --git a/openerp/addons/base/i18n/eu.po b/openerp/addons/base/i18n/eu.po index 8b92327e5ac..0c1ac0ac100 100644 --- a/openerp/addons/base/i18n/eu.po +++ b/openerp/addons/base/i18n/eu.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fa.po b/openerp/addons/base/i18n/fa.po index 584d51a545e..517a9b87e19 100644 --- a/openerp/addons/base/i18n/fa.po +++ b/openerp/addons/base/i18n/fa.po @@ -5496,7 +5496,7 @@ msgstr "برگردان‌ها" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "پیمایش شمارگانی" #. module: base diff --git a/openerp/addons/base/i18n/fa_AF.po b/openerp/addons/base/i18n/fa_AF.po index d730070ecf9..1e0010a8fb4 100644 --- a/openerp/addons/base/i18n/fa_AF.po +++ b/openerp/addons/base/i18n/fa_AF.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/fi.po b/openerp/addons/base/i18n/fi.po index 16526bf9807..c47ec894821 100644 --- a/openerp/addons/base/i18n/fi.po +++ b/openerp/addons/base/i18n/fi.po @@ -5664,7 +5664,7 @@ msgstr "Käännökset" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Täytenumerot" #. module: base diff --git a/openerp/addons/base/i18n/fr.po b/openerp/addons/base/i18n/fr.po index 6fb9188fd3c..6ce408bc01a 100644 --- a/openerp/addons/base/i18n/fr.po +++ b/openerp/addons/base/i18n/fr.po @@ -5717,7 +5717,7 @@ msgstr "Traductions" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Remplissage" #. module: base diff --git a/openerp/addons/base/i18n/gl.po b/openerp/addons/base/i18n/gl.po index 8547223c29c..b2e33836902 100644 --- a/openerp/addons/base/i18n/gl.po +++ b/openerp/addons/base/i18n/gl.po @@ -5695,7 +5695,7 @@ msgstr "Traducións" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Número de enchido" #. module: base diff --git a/openerp/addons/base/i18n/he.po b/openerp/addons/base/i18n/he.po index 0e14797c6ee..07fda35ca86 100644 --- a/openerp/addons/base/i18n/he.po +++ b/openerp/addons/base/i18n/he.po @@ -5472,7 +5472,7 @@ msgstr "תרגומים" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/hr.po b/openerp/addons/base/i18n/hr.po index e82d8fb80cc..f7186b309ac 100644 --- a/openerp/addons/base/i18n/hr.po +++ b/openerp/addons/base/i18n/hr.po @@ -5553,7 +5553,7 @@ msgstr "Prijevodi" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Dopunjavanje na duljinu" #. module: base diff --git a/openerp/addons/base/i18n/hu.po b/openerp/addons/base/i18n/hu.po index 043b188ece7..35e0b0fb423 100644 --- a/openerp/addons/base/i18n/hu.po +++ b/openerp/addons/base/i18n/hu.po @@ -5666,8 +5666,8 @@ msgstr "Fordítások" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" -msgstr "Number padding" +msgid "Number Padding" +msgstr "Number Padding" #. module: base #: view:ir.actions.report.xml:0 diff --git a/openerp/addons/base/i18n/hy.po b/openerp/addons/base/i18n/hy.po index f47eb825bc2..2ab57b9b7fa 100644 --- a/openerp/addons/base/i18n/hy.po +++ b/openerp/addons/base/i18n/hy.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/id.po b/openerp/addons/base/i18n/id.po index 969f42eb804..dc1d81aa8bb 100644 --- a/openerp/addons/base/i18n/id.po +++ b/openerp/addons/base/i18n/id.po @@ -5435,7 +5435,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/is.po b/openerp/addons/base/i18n/is.po index f0973c0a8e4..6f29f97bb15 100644 --- a/openerp/addons/base/i18n/is.po +++ b/openerp/addons/base/i18n/is.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/it.po b/openerp/addons/base/i18n/it.po index 3a106c0498a..bbd01e7eaaf 100644 --- a/openerp/addons/base/i18n/it.po +++ b/openerp/addons/base/i18n/it.po @@ -5713,7 +5713,7 @@ msgstr "Traduzioni" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Riempimento Numero" #. module: base diff --git a/openerp/addons/base/i18n/ja.po b/openerp/addons/base/i18n/ja.po index 2d6310e5312..b3f7126abf8 100644 --- a/openerp/addons/base/i18n/ja.po +++ b/openerp/addons/base/i18n/ja.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/kk.po b/openerp/addons/base/i18n/kk.po index 1df9844334b..2473306dac8 100644 --- a/openerp/addons/base/i18n/kk.po +++ b/openerp/addons/base/i18n/kk.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ko.po b/openerp/addons/base/i18n/ko.po index 0025fb970e6..d4552dceb23 100644 --- a/openerp/addons/base/i18n/ko.po +++ b/openerp/addons/base/i18n/ko.po @@ -5457,7 +5457,7 @@ msgstr "번역" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/lt.po b/openerp/addons/base/i18n/lt.po index 2a31023df0f..f497c904fbd 100644 --- a/openerp/addons/base/i18n/lt.po +++ b/openerp/addons/base/i18n/lt.po @@ -5464,7 +5464,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/lt_LT.po b/openerp/addons/base/i18n/lt_LT.po index 7aee4518a19..5c98c806928 100644 --- a/openerp/addons/base/i18n/lt_LT.po +++ b/openerp/addons/base/i18n/lt_LT.po @@ -4618,7 +4618,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/lv.po b/openerp/addons/base/i18n/lv.po index cd1ef4c77fe..8b654b76800 100644 --- a/openerp/addons/base/i18n/lv.po +++ b/openerp/addons/base/i18n/lv.po @@ -5514,7 +5514,7 @@ msgstr "Tulkojumi" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Ciparu vietas" #. module: base diff --git a/openerp/addons/base/i18n/mk.po b/openerp/addons/base/i18n/mk.po index bb8f47fcf7c..d9b5395a888 100644 --- a/openerp/addons/base/i18n/mk.po +++ b/openerp/addons/base/i18n/mk.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/mn.po b/openerp/addons/base/i18n/mn.po index 12c8460790f..fa355ed7b11 100644 --- a/openerp/addons/base/i18n/mn.po +++ b/openerp/addons/base/i18n/mn.po @@ -5533,7 +5533,7 @@ msgstr "Орчуулгууд" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Тоон дугаарын урт" #. module: base diff --git a/openerp/addons/base/i18n/nb.po b/openerp/addons/base/i18n/nb.po index c62673f2b19..17bc1c0e472 100644 --- a/openerp/addons/base/i18n/nb.po +++ b/openerp/addons/base/i18n/nb.po @@ -5530,7 +5530,7 @@ msgstr "Oversettelser" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Bunnfyll" #. module: base diff --git a/openerp/addons/base/i18n/nl.po b/openerp/addons/base/i18n/nl.po index 2bb60f29b38..831941c72a6 100644 --- a/openerp/addons/base/i18n/nl.po +++ b/openerp/addons/base/i18n/nl.po @@ -5702,7 +5702,7 @@ msgstr "Vertalingen" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Nummer verspringing" #. module: base diff --git a/openerp/addons/base/i18n/nl_BE.po b/openerp/addons/base/i18n/nl_BE.po index 09b17071edd..aba44535fa2 100644 --- a/openerp/addons/base/i18n/nl_BE.po +++ b/openerp/addons/base/i18n/nl_BE.po @@ -5447,7 +5447,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/nl_NL.po b/openerp/addons/base/i18n/nl_NL.po index 704c25a9d46..eeef0f9010e 100644 --- a/openerp/addons/base/i18n/nl_NL.po +++ b/openerp/addons/base/i18n/nl_NL.po @@ -4796,7 +4796,7 @@ msgstr "Vertalingen" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Nummer verspringing" #. module: base diff --git a/openerp/addons/base/i18n/pl.po b/openerp/addons/base/i18n/pl.po index 9b8f0c8769c..417976cebd6 100644 --- a/openerp/addons/base/i18n/pl.po +++ b/openerp/addons/base/i18n/pl.po @@ -5612,7 +5612,7 @@ msgstr "Tłumaczenia" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Liczba cyfr" #. module: base diff --git a/openerp/addons/base/i18n/pt.po b/openerp/addons/base/i18n/pt.po index 88b097ffe71..03f8b93ede1 100644 --- a/openerp/addons/base/i18n/pt.po +++ b/openerp/addons/base/i18n/pt.po @@ -5591,7 +5591,7 @@ msgstr "Traduções" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Dígitos do número" #. module: base diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po index 254c642a060..e8c5a66dada 100644 --- a/openerp/addons/base/i18n/pt_BR.po +++ b/openerp/addons/base/i18n/pt_BR.po @@ -5687,7 +5687,7 @@ msgstr "Traduções" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Preencher número" #. module: base diff --git a/openerp/addons/base/i18n/ro.po b/openerp/addons/base/i18n/ro.po index 7f6e34b2edc..5d1f4e6012d 100644 --- a/openerp/addons/base/i18n/ro.po +++ b/openerp/addons/base/i18n/ro.po @@ -5555,7 +5555,7 @@ msgstr "Traduceri" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/ru.po b/openerp/addons/base/i18n/ru.po index 48133981214..33388d00882 100644 --- a/openerp/addons/base/i18n/ru.po +++ b/openerp/addons/base/i18n/ru.po @@ -5689,7 +5689,7 @@ msgstr "Переводы" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Выравнивание чисел" #. module: base diff --git a/openerp/addons/base/i18n/sk.po b/openerp/addons/base/i18n/sk.po index df5f44b9ef4..267dc5a9223 100644 --- a/openerp/addons/base/i18n/sk.po +++ b/openerp/addons/base/i18n/sk.po @@ -5598,7 +5598,7 @@ msgstr "Preklady" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Zarovanie čísla" #. module: base diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po index 22d06500f88..5e6d5eb5119 100644 --- a/openerp/addons/base/i18n/sl.po +++ b/openerp/addons/base/i18n/sl.po @@ -5650,7 +5650,7 @@ msgstr "Prevodi" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Zapolnitev številke" #. module: base diff --git a/openerp/addons/base/i18n/sq.po b/openerp/addons/base/i18n/sq.po index 4d38cd56221..bb97ede3852 100644 --- a/openerp/addons/base/i18n/sq.po +++ b/openerp/addons/base/i18n/sq.po @@ -5430,7 +5430,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sr.po b/openerp/addons/base/i18n/sr.po index 04a1487c320..b174a0b5a2b 100644 --- a/openerp/addons/base/i18n/sr.po +++ b/openerp/addons/base/i18n/sr.po @@ -5575,7 +5575,7 @@ msgstr "Prevodi" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Dopunjavanje brojeva" #. module: base diff --git a/openerp/addons/base/i18n/sr@latin.po b/openerp/addons/base/i18n/sr@latin.po index a545d3854a8..2aeaeb0279b 100644 --- a/openerp/addons/base/i18n/sr@latin.po +++ b/openerp/addons/base/i18n/sr@latin.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/sv.po b/openerp/addons/base/i18n/sv.po index 5dd00cab0ba..9422185f5da 100644 --- a/openerp/addons/base/i18n/sv.po +++ b/openerp/addons/base/i18n/sv.po @@ -5624,7 +5624,7 @@ msgstr "Översättningar" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Numerisk utfyllnad" #. module: base diff --git a/openerp/addons/base/i18n/th.po b/openerp/addons/base/i18n/th.po index d785c5d635b..312b25c8e63 100644 --- a/openerp/addons/base/i18n/th.po +++ b/openerp/addons/base/i18n/th.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tlh.po b/openerp/addons/base/i18n/tlh.po index dede310a722..226f568ed46 100644 --- a/openerp/addons/base/i18n/tlh.po +++ b/openerp/addons/base/i18n/tlh.po @@ -5430,7 +5430,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/tr.po b/openerp/addons/base/i18n/tr.po index a1661ed041e..4311bcb01a8 100644 --- a/openerp/addons/base/i18n/tr.po +++ b/openerp/addons/base/i18n/tr.po @@ -5637,7 +5637,7 @@ msgstr "Çeviriler" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Numara dolgusu" #. module: base diff --git a/openerp/addons/base/i18n/uk.po b/openerp/addons/base/i18n/uk.po index a024978394c..6c1f6ffeb02 100644 --- a/openerp/addons/base/i18n/uk.po +++ b/openerp/addons/base/i18n/uk.po @@ -5495,7 +5495,7 @@ msgstr "Переклади" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Вирівнювання номерів" #. module: base diff --git a/openerp/addons/base/i18n/uk_UA.po b/openerp/addons/base/i18n/uk_UA.po index c1923fd44a9..c984308a4de 100644 --- a/openerp/addons/base/i18n/uk_UA.po +++ b/openerp/addons/base/i18n/uk_UA.po @@ -4636,7 +4636,7 @@ msgstr "Переклади" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "Вирівнювання номерів" #. module: base diff --git a/openerp/addons/base/i18n/ur.po b/openerp/addons/base/i18n/ur.po index 2457121dad1..4deaed2489c 100644 --- a/openerp/addons/base/i18n/ur.po +++ b/openerp/addons/base/i18n/ur.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/vi.po b/openerp/addons/base/i18n/vi.po index 417c64daba6..ba03de09502 100644 --- a/openerp/addons/base/i18n/vi.po +++ b/openerp/addons/base/i18n/vi.po @@ -5468,7 +5468,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_CN.po b/openerp/addons/base/i18n/zh_CN.po index ccc8619e189..a633854008f 100644 --- a/openerp/addons/base/i18n/zh_CN.po +++ b/openerp/addons/base/i18n/zh_CN.po @@ -5471,7 +5471,7 @@ msgstr "翻译" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "数字位数" #. module: base diff --git a/openerp/addons/base/i18n/zh_HK.po b/openerp/addons/base/i18n/zh_HK.po index 75dd21f04ff..36c46a3b93c 100644 --- a/openerp/addons/base/i18n/zh_HK.po +++ b/openerp/addons/base/i18n/zh_HK.po @@ -5431,7 +5431,7 @@ msgstr "" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/i18n/zh_TW.po b/openerp/addons/base/i18n/zh_TW.po index 53610346f81..c6b6ac26afa 100644 --- a/openerp/addons/base/i18n/zh_TW.po +++ b/openerp/addons/base/i18n/zh_TW.po @@ -5447,7 +5447,7 @@ msgstr "翻譯" #. module: base #: field:ir.sequence,padding:0 -msgid "Number padding" +msgid "Number Padding" msgstr "" #. module: base diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 4d10eefe75e..b0995c914d0 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -65,7 +65,7 @@ class ir_sequence(openerp.osv.osv.osv): 'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"), 'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"), 'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"), - 'padding' : openerp.osv.fields.integer('Number padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."), + 'padding' : openerp.osv.fields.integer('Number Padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."), 'company_id': openerp.osv.fields.many2one('res.company', 'Company'), } _defaults = { From 538cc0e92f9fbc993bec5a224de4c3f38b9a13e6 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 16:15:20 +0200 Subject: [PATCH 09/14] [FIX] ir_sequence: typo in read(). bzr revid: vmt@openerp.com-20110928141520-9yx9sogoetizb9nn --- openerp/addons/base/ir/ir_sequence.py | 2 +- tests/test_ir_sequence.py | 143 +++++++++++++++----------- 2 files changed, 86 insertions(+), 59 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index b0995c914d0..34a4b0144eb 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -104,7 +104,7 @@ class ir_sequence(openerp.osv.osv.osv): def write(self, cr, uid, ids, values, context=None): ids = ids if isinstance(ids, (list, tuple)) else [ids] new_implementation = values.get('implementation') - rows = self.read(cr, uid, ids, ['id,' 'implementation', + rows = self.read(cr, uid, ids, ['implementation', 'number_increment', 'number_next'], context) super(ir_sequence, self).write(cr, uid, ids, values, context) diff --git a/tests/test_ir_sequence.py b/tests/test_ir_sequence.py index 0fc7aec5b50..13c40dd6eb3 100644 --- a/tests/test_ir_sequence.py +++ b/tests/test_ir_sequence.py @@ -33,51 +33,43 @@ class test_ir_sequence_standard(unittest2.TestCase): def test_ir_sequence_create(self): """ Try to create a sequence object. """ cr = cursor() - try: - d = dict(code='test_sequence_type', name='Test sequence type') - c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) - assert c - d = dict(code='test_sequence_type', name='Test sequence') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - finally: - cr.close() + d = dict(code='test_sequence_type', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type', name='Test sequence') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + cr.close() def test_ir_sequence_search(self): """ Try a search. """ cr = cursor() - try: - ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, [], {}) - assert ids - cr.commit() - finally: - cr.close() + ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, [], {}) + assert ids + cr.commit() + cr.close() def test_ir_sequence_draw(self): """ Try to draw a number. """ cr = cursor() - try: - n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n - cr.commit() - finally: - cr.close() + n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n + cr.commit() + cr.close() def test_ir_sequence_draw_twice(self): """ Try to draw a number from two transactions. """ cr0 = cursor() cr1 = cursor() - try: - n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n0 - n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n1 - cr0.commit() - cr1.commit() - finally: - cr0.close() - cr1.close() + n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n0 + n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type', {}) + assert n1 + cr0.commit() + cr1.commit() + cr0.close() + cr1.close() class test_ir_sequence_no_gap(unittest2.TestCase): """ Copy of the previous tests for a 'No gap' sequence. """ @@ -85,27 +77,23 @@ class test_ir_sequence_no_gap(unittest2.TestCase): def test_ir_sequence_create_no_gap(self): """ Try to create a sequence object. """ cr = cursor() - try: - d = dict(code='test_sequence_type_2', name='Test sequence type') - c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) - assert c - d = dict(code='test_sequence_type_2', name='Test sequence', - implementation='no_gap') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - finally: - cr.close() + d = dict(code='test_sequence_type_2', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_2', name='Test sequence', + implementation='no_gap') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + cr.close() def test_ir_sequence_draw_no_gap(self): """ Try to draw a number. """ cr = cursor() - try: - n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type_2', {}) - assert n - cr.commit() - finally: - cr.close() + n = registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type_2', {}) + assert n + cr.commit() + cr.close() def test_ir_sequence_draw_twice_no_gap(self): """ Try to draw a number from two transactions. @@ -113,15 +101,54 @@ class test_ir_sequence_no_gap(unittest2.TestCase): """ cr0 = cursor() cr1 = cursor() - try: - msg_re = '^could not obtain lock on row in relation "ir_sequence"$' - with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re): - n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) - assert n0 - n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) - finally: - cr0.close() - cr1.close() + msg_re = '^could not obtain lock on row in relation "ir_sequence"$' + with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re): + n0 = registry('ir.sequence').get(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) + assert n0 + n1 = registry('ir.sequence').get(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) + cr0.close() + cr1.close() + +class test_ir_sequence_change_implementation(unittest2.TestCase): + """ Create sequence objects and change their ``implementation`` field. """ + + def test_ir_sequence_1_create(self): + """ Try to create a sequence object. """ + cr = cursor() + d = dict(code='test_sequence_type_3', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_3', name='Test sequence') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_4', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_4', name='Test sequence', + implementation='no_gap') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + cr.close() + + def test_ir_sequence_2_write(self): + cr = cursor() + ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, + [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {}) + registry('ir.sequence').write(cr, ADMIN_USER_ID, ids, + {'implementation': 'standard'}, {}) + registry('ir.sequence').write(cr, ADMIN_USER_ID, ids, + {'implementation': 'no_gap'}, {}) + cr.commit() + cr.close() + + def test_ir_sequence_3_unlink(self): + cr = cursor() + ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, + [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {}) + registry('ir.sequence').unlink(cr, ADMIN_USER_ID, ids, {}) + cr.commit() + cr.close() if __name__ == '__main__': From b917742f15c6c801120d49277e2d8b846c9e7f36 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 28 Sep 2011 17:17:04 +0200 Subject: [PATCH 10/14] [IMP] ir_sequence: added a simple test. bzr revid: vmt@openerp.com-20110928151704-tqsr5h8zqs0vr32f --- tests/test_ir_sequence.py | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test_ir_sequence.py b/tests/test_ir_sequence.py index 13c40dd6eb3..8a4731d524f 100644 --- a/tests/test_ir_sequence.py +++ b/tests/test_ir_sequence.py @@ -6,6 +6,7 @@ # OPENERP_DATABASE=yy nosetests tests/test_ir_sequence.py # > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ # OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence +# This assume an existing database. import os import psycopg2 import time @@ -150,6 +151,47 @@ class test_ir_sequence_change_implementation(unittest2.TestCase): cr.commit() cr.close() +class test_ir_sequence_generate(unittest2.TestCase): + """ Create sequence objects and generate some values. """ + + def test_ir_sequence_create(self): + """ Try to create a sequence object. """ + cr = cursor() + d = dict(code='test_sequence_type_5', name='Test sequence type') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_5', name='Test sequence') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + cr.close() + + cr = cursor() + f = lambda *a: registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type_5', {}) + assert all(str(x) == f() for x in xrange(1,1000)) + cr.commit() + cr.close() + + def test_ir_sequence_create_no_gap(self): + """ Try to create a sequence object. """ + cr = cursor() + d = dict(code='test_sequence_type_6', name='Test sequence type', + implementation='no_gap') + c = registry('ir.sequence.type').create(cr, ADMIN_USER_ID, d, {}) + assert c + d = dict(code='test_sequence_type_6', name='Test sequence') + c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) + assert c + cr.commit() + cr.close() + + cr = cursor() + f = lambda *a: registry('ir.sequence').get(cr, ADMIN_USER_ID, 'test_sequence_type_6', {}) + assert all(str(x) == f() for x in xrange(1,1000)) + cr.commit() + cr.close() + + if __name__ == '__main__': unittest2.main() From dc993b507ecf876a150c054ff0c4b8823e0314f2 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 29 Sep 2011 14:27:53 +0200 Subject: [PATCH 11/14] [IMP] ir_sequence: change API, deprecate old one. bzr revid: vmt@openerp.com-20110929122753-19middna4b782tcy --- openerp/addons/base/ir/ir_sequence.py | 93 ++++++++++++++++----------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 34a4b0144eb..3a3a6d4e5e2 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -19,10 +19,13 @@ # ############################################################################## +import logging import time import openerp +_logger = logging.getLogger('ir_sequence') + class ir_sequence_type(openerp.osv.osv.osv): _name = 'ir.sequence.type' _order = 'name' @@ -39,9 +42,6 @@ def _code_get(self, cr, uid, context={}): cr.execute('select code, name from ir_sequence_type') return cr.fetchall() -IMPLEMENTATION_SELECTION = \ - [('standard', 'Standard'), ('no_gap', 'No gap')] - class ir_sequence(openerp.osv.osv.osv): """ Sequence model. @@ -56,7 +56,8 @@ class ir_sequence(openerp.osv.osv.osv): 'name': openerp.osv.fields.char('Name', size=64, required=True), 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64, required=True), 'implementation': openerp.osv.fields.selection( # TODO update the view - IMPLEMENTATION_SELECTION, 'Implementation', required=True, + [('standard', 'Standard'), ('no_gap', 'No gap')], + 'Implementation', required=True, help="Two sequence object implementations are offered: Standard " "and 'No gap'. The later is slower than the former but forbids any" " gap in the sequence (while they are possible in the former)."), @@ -144,53 +145,71 @@ class ir_sequence(openerp.osv.osv.osv): 'sec': time.strftime('%S', t), } - # TODO rename 'test' to 'code_or_id' in account/sequence. + def next_by_id(self, cr, uid, sequence_id, context=None): + """ Draw an interpolated string using the specified sequence.""" + self.check_read(cr, uid) + res = self._select_by_code_or_id(cr, uid, sequence_id, + 'id', False, context) + return self._next(cr, uid, res, context) + + def next_by_code(self, cr, uid, sequence_code, context=None): + """ Draw an interpolated string using the specified sequence.""" + self.check_read(cr, uid) + res = self._select_by_code_or_id(cr, uid, sequence_code, + 'code', False, context) + return self._next(cr, uid, res, context) + def get_id(self, cr, uid, sequence_code_or_id, code_or_id='id', context=None): """ Draw an interpolated string using the specified sequence. The sequence to use is specified by the ``sequence_code_or_id`` argument, which can be a code or an id (as controlled by the - ``code_or_id`` argument. + ``code_or_id`` argument. This method is deprecated. """ - self.check_read(cr, uid) - res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, - code_or_id, False, context) - - if not res: - return False - - if res['implementation'] == 'standard': - cr.execute(""" - SELECT nextval('ir_sequence_%03d') - """ % res['id']) - res['number_next'] = cr.fetchone() + _logger.warning("ir_sequence.get() and ir_sequence.get_id() are deprecated. " + "Please use ir_sequence.next_by_code() or ir_sequence.next_by_id().") + if code_or_id == 'id': + return self.next_by_id(cr, uid, sequence_code_or_id, context) else: - # Read again with FOR UPDATE NO WAIT. - res = self._select_by_code_or_id(cr, uid, sequence_code_or_id, - code_or_id, True, context) - cr.execute(""" - UPDATE ir_sequence - SET number_next=number_next+number_increment - WHERE id=%s - """, (res['id'],)) - - d = self._interpolation_dict() - interpolated_prefix = self._interpolate(res['prefix'], d) - interpolated_suffix = self._interpolate(res['suffix'], d) - if res['number_next']: - return interpolated_prefix + '%%0%sd' % res['padding'] % \ - res['number_next'] + interpolated_suffix - else: - # TODO what is this case used for ? - return interpolated_prefix + interpolated_suffix + return self.next_by_code(cr, uid, sequence_code_or_id, context) def get(self, cr, uid, code, context=None): """ Draw an interpolated string using the specified sequence. - The sequence to use is specified by its code. + The sequence to use is specified by its code. This method is + deprecated. """ return self.get_id(cr, uid, code, 'code', context) + def _next(self, cr, uid, sequence, context=None): + if not sequence: + return False + + if sequence['implementation'] == 'standard': + cr.execute(""" + SELECT nextval('ir_sequence_%03d') + """ % sequence['id']) + sequence['number_next'] = cr.fetchone() + else: + # Read again with FOR UPDATE NO WAIT. + sequence = self._select_by_code_or_id(cr, uid, sequence['id'], + 'id', True, context) + cr.execute(""" + UPDATE ir_sequence + SET number_next=number_next+number_increment + WHERE id=%s + """, (sequence['id'],)) + + d = self._interpolation_dict() + interpolated_prefix = self._interpolate(sequence['prefix'], d) + interpolated_suffix = self._interpolate(sequence['suffix'], d) + if sequence['number_next']: + return interpolated_prefix + '%%0%sd' % sequence['padding'] % \ + sequence['number_next'] + interpolated_suffix + else: + # TODO what is this case used for ? + return interpolated_prefix + interpolated_suffix + def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, for_update_no_wait, context=None): """ Read a sequence object. From 1381ac139ed33e858ae6af34f61d04becbcc06bf Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 29 Sep 2011 15:47:58 +0200 Subject: [PATCH 12/14] [IMP] ir_sequence: (code, company_id) is unique, even for company_id IS NULL. bzr revid: vmt@openerp.com-20110929134758-793vqith9pfcvs7w --- openerp/addons/base/ir/ir_sequence.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 3a3a6d4e5e2..56a7da9629b 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -78,6 +78,20 @@ class ir_sequence(openerp.osv.osv.osv): 'padding' : 0, } + def init(self, cr): + # CONSTRAINT/UNIQUE INDEX on (code, company_id) + # /!\ The unique constraint 'unique_name_company_id' is not sufficient, because SQL92 + # only support field names in constraint definitions, and we need a function here: + # we need to special-case company_id to treat all NULL company_id as equal, otherwise + # we would allow duplicate (code, NULL) ir_sequences. + cr.execute(""" + SELECT indexname FROM pg_indexes WHERE indexname = + 'ir_sequence_unique_code_company_id_idx'""") + if not cr.fetchone(): + cr.execute(""" + CREATE UNIQUE INDEX ir_sequence_unique_code_company_id_idx + ON ir_sequence (code, (COALESCE(company_id,-1)))""") + def create(self, cr, uid, values, context=None): values = self._add_missing_default_values(cr, uid, values, context) go = super(ir_sequence, self).create \ @@ -226,8 +240,6 @@ class ir_sequence(openerp.osv.osv.osv): WHERE %s=%%s AND active=true AND (company_id in %%s or company_id is NULL) - ORDER BY company_id, id - LIMIT 1 %s """ % (code_or_id, funw), (sequence_code_or_id, tuple(company_ids))) From 83fdc271e6c0606dd91d266680a81b9596da27fa Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 30 Sep 2011 17:23:45 +0200 Subject: [PATCH 13/14] [FIX] ir_sequence: temporary fix: no (code,company) unique constraint. bzr revid: vmt@openerp.com-20110930152345-cwmbotwvxaafb32f --- openerp/addons/base/ir/ir_sequence.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 56a7da9629b..b862c4cabfc 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -79,6 +79,7 @@ class ir_sequence(openerp.osv.osv.osv): } def init(self, cr): + return # Don't do the following index yet. # CONSTRAINT/UNIQUE INDEX on (code, company_id) # /!\ The unique constraint 'unique_name_company_id' is not sufficient, because SQL92 # only support field names in constraint definitions, and we need a function here: From 997d9f41782cba16eb50abf18b08d877e020414d Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Fri, 30 Sep 2011 20:38:06 +0200 Subject: [PATCH 14/14] [IMP] minor simplification and style change (avoid inline if, less snobby, more readable) bzr revid: al@openerp.com-20110930183806-6r78rt62cebc82iv --- openerp/addons/base/ir/ir_sequence.py | 207 ++++++++++++-------------- 1 file changed, 95 insertions(+), 112 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index b862c4cabfc..51b57a2ffbe 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -93,24 +93,48 @@ class ir_sequence(openerp.osv.osv.osv): CREATE UNIQUE INDEX ir_sequence_unique_code_company_id_idx ON ir_sequence (code, (COALESCE(company_id,-1)))""") - def create(self, cr, uid, values, context=None): - values = self._add_missing_default_values(cr, uid, values, context) - go = super(ir_sequence, self).create \ - if values['implementation'] == 'no_gap' else self.create_postgres - return go(cr, uid, values, context) + def _create_sequence(self, cr, id, number_increment, number_next): + """ Create a PostreSQL sequence. - def create_postgres(self, cr, uid, values, context=None): - """ Create a fast, gaps-allowed PostgreSQL sequence. - - :param values: same argument than for ``create()`` but the keys - ``number_increment`` and ``number_next`` must be present. - ``_add_missing_default_values()`` can be used to this effect. - :return: id of the newly created record + There is no access rights check. """ - id = super(ir_sequence, self).create(cr, uid, values, context) - self._create_sequence(cr, id, - values['number_increment'], values['number_next']) - return id + assert isinstance(id, (int, long)) + sql = "CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s" % id + cr.execute(sql, (number_increment, number_next)) + + def _drop_sequence(self, cr, ids): + """ Drop the PostreSQL sequence if it exists. + + There is no access rights check. + """ + + ids = ids if isinstance(ids, (list, tuple)) else [ids] + assert all(isinstance(i, (int, long)) for i in ids), \ + "Only ids in (int, long) allowed." + names = ','.join('ir_sequence_%03d' % i for i in ids) + + # RESTRICT is the default; it prevents dropping the sequence if an + # object depends on it. + cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names) + + def _alter_sequence(self, cr, id, number_increment, number_next): + """ Alter a PostreSQL sequence. + + There is no access rights check. + """ + assert isinstance(id, (int, long)) + cr.execute(""" + ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s + """ % id, (number_increment, number_next)) + + def create(self, cr, uid, values, context=None): + """ Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used. + """ + values = self._add_missing_default_values(cr, uid, values, context) + values['id'] = super(ir_sequence, self).create(cr, uid, values, context) + if values['implementation'] == 'standard': + f = self._create_sequence(cr, values['id'], values['number_increment'], values['number_next']) + return values['id'] def unlink(self, cr, uid, ids, context=None): super(ir_sequence, self).unlink(cr, uid, ids, context) @@ -118,12 +142,12 @@ class ir_sequence(openerp.osv.osv.osv): return True def write(self, cr, uid, ids, values, context=None): - ids = ids if isinstance(ids, (list, tuple)) else [ids] + if not isinstance(ids, (list, tuple)): + ids = [ids] new_implementation = values.get('implementation') - rows = self.read(cr, uid, ids, ['implementation', - 'number_increment', 'number_next'], context) + rows = self.read(cr, uid, ids, ['implementation', 'number_increment', 'number_next'], context) super(ir_sequence, self).write(cr, uid, ids, values, context) - + for row in rows: # 4 cases: we test the previous impl. against the new one. if row['implementation'] == 'standard': @@ -142,7 +166,9 @@ class ir_sequence(openerp.osv.osv.osv): return True def _interpolate(self, s, d): - return s % d if s else '' + if s: + return s % d + return '' def _interpolation_dict(self): t = time.localtime() # Actually, the server is always in UTC. @@ -160,18 +186,62 @@ class ir_sequence(openerp.osv.osv.osv): 'sec': time.strftime('%S', t), } + def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, for_update_no_wait, context=None): + """ Read a sequence object. + + There is no access rights check on the sequence itself. + """ + assert code_or_id in ('code', 'id') + res_company = self.pool.get('res.company') + company_ids = res_company.search(cr, uid, [], context=context) + sql = """ + SELECT id, number_next, prefix, suffix, padding, implementation + FROM ir_sequence + WHERE %s=%%s + AND active=true + AND (company_id in %%s or company_id is NULL) + """ % code_or_id + if for_update_no_wait: + sql += 'FOR UPDATE NOWAIT' + cr.execute(sql, (sequence_code_or_id, tuple(company_ids))) + return cr.dictfetchone() + + def _next(self, cr, uid, sequence, context=None): + if not sequence: + return False + + if sequence['implementation'] == 'standard': + cr.execute("SELECT nextval('ir_sequence_%03d')" % sequence['id']) + sequence['number_next'] = cr.fetchone() + else: + # Read again with FOR UPDATE NO WAIT. + sequence = self._select_by_code_or_id(cr, uid, sequence['id'], 'id', True, context) + cr.execute(""" + UPDATE ir_sequence + SET number_next=number_next+number_increment + WHERE id=%s + """, (sequence['id'],)) + + d = self._interpolation_dict() + interpolated_prefix = self._interpolate(sequence['prefix'], d) + interpolated_suffix = self._interpolate(sequence['suffix'], d) + if sequence['number_next']: + return interpolated_prefix + '%%0%sd' % sequence['padding'] % \ + sequence['number_next'] + interpolated_suffix + else: + # TODO what is this case used for ? + return interpolated_prefix + interpolated_suffix + def next_by_id(self, cr, uid, sequence_id, context=None): """ Draw an interpolated string using the specified sequence.""" self.check_read(cr, uid) - res = self._select_by_code_or_id(cr, uid, sequence_id, - 'id', False, context) + res = self._select_by_code_or_id(cr, uid, sequence_id, 'id', False, context) return self._next(cr, uid, res, context) def next_by_code(self, cr, uid, sequence_code, context=None): """ Draw an interpolated string using the specified sequence.""" self.check_read(cr, uid) - res = self._select_by_code_or_id(cr, uid, sequence_code, - 'code', False, context) + res = self._select_by_code_or_id(cr, uid, sequence_code, 'code', False, context) return self._next(cr, uid, res, context) def get_id(self, cr, uid, sequence_code_or_id, code_or_id='id', context=None): @@ -196,92 +266,5 @@ class ir_sequence(openerp.osv.osv.osv): """ return self.get_id(cr, uid, code, 'code', context) - def _next(self, cr, uid, sequence, context=None): - if not sequence: - return False - - if sequence['implementation'] == 'standard': - cr.execute(""" - SELECT nextval('ir_sequence_%03d') - """ % sequence['id']) - sequence['number_next'] = cr.fetchone() - else: - # Read again with FOR UPDATE NO WAIT. - sequence = self._select_by_code_or_id(cr, uid, sequence['id'], - 'id', True, context) - cr.execute(""" - UPDATE ir_sequence - SET number_next=number_next+number_increment - WHERE id=%s - """, (sequence['id'],)) - - d = self._interpolation_dict() - interpolated_prefix = self._interpolate(sequence['prefix'], d) - interpolated_suffix = self._interpolate(sequence['suffix'], d) - if sequence['number_next']: - return interpolated_prefix + '%%0%sd' % sequence['padding'] % \ - sequence['number_next'] + interpolated_suffix - else: - # TODO what is this case used for ? - return interpolated_prefix + interpolated_suffix - - def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, - for_update_no_wait, context=None): - """ Read a sequence object. - - There is no access rights check on the sequence itself. - """ - assert code_or_id in ('code', 'id') - res_company = self.pool.get('res.company') - company_ids = res_company.search(cr, uid, [], context=context) - funw = 'FOR UPDATE NOWAIT' if for_update_no_wait else '' - cr.execute(""" - SELECT id, number_next, prefix, suffix, padding, implementation - FROM ir_sequence - WHERE %s=%%s - AND active=true - AND (company_id in %%s or company_id is NULL) - %s - """ % (code_or_id, funw), - (sequence_code_or_id, tuple(company_ids))) - return cr.dictfetchone() - - def _create_sequence(self, cr, id, number_increment, number_next): - """ Create a PostreSQL sequence. - - There is no access rights check. - """ - assert isinstance(id, (int, long)) - cr.execute(""" - CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s - """ % id, (number_increment, number_next)) - - def _drop_sequence(self, cr, ids): - """ Drop the PostreSQL sequence if it exists. - - There is no access rights check. - """ - - ids = ids if isinstance(ids, (list, tuple)) else [ids] - assert all(isinstance(i, (int, long)) for i in ids), \ - "Only ids in (int, long) allowed." - names = ','.join('ir_sequence_%03d' % i for i in ids) - - # RESTRICT is the default; it prevents dropping the sequence if an - # object depends on it. - cr.execute(""" - DROP SEQUENCE IF EXISTS %s RESTRICT - """ % names) - - def _alter_sequence(self, cr, id, number_increment, number_next): - """ Alter a PostreSQL sequence. - - There is no access rights check. - """ - assert isinstance(id, (int, long)) - cr.execute(""" - ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s - """ % id, (number_increment, number_next)) - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: