Merge lp:~openerp-dev/openobject-server/7.0-sequence-next-fix-csn into lp:openobject-server/7.0

Proposed by Cedric Snauwaert (OpenERP)
Status: Merged
Merged at revision: 4978
Proposed branch: lp:~openerp-dev/openobject-server/7.0-sequence-next-fix-csn
Merge into: lp:openobject-server/7.0
Diff against target: 129 lines (+49/-10)
2 files modified
openerp/addons/base/ir/ir_sequence.py (+47/-8)
openerp/addons/base/ir/ir_sequence_view.xml (+2/-2)
To merge this branch: bzr merge lp:~openerp-dev/openobject-server/7.0-sequence-next-fix-csn
Reviewer Review Type Date Requested Status
Olivier Dony (Odoo) Approve
qdp (OpenERP) Pending
Review via email: mp+164363@code.launchpad.net

Description of the change

Change in ir_sequence to have information on current_number and better warning message in case the format of prefix/suffix isn't correct

To post a comment you must log in.
4978. By Cedric Snauwaert (OpenERP)

[FIX]ir_sequence: better args definition

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Looks good to me except the default value of number_next when passed to _alter_sequence(), that should be None rather than 0, otherwise you're forbidding resetting the sequence to 0, which is perfectly legit.

Note: the patch needs to be credited to Therp, as you reused a large part of their merge prop. We can do that when merging, but please be careful to do that at commit-level directly next time, this is important.

review: Needs Fixing
Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

I see that the number_next default to None is already fixed, thanks!

review: Approve
Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Merged. I also changed the label from "Actual Next Number" back to "Next Number" because `Actual` conveys a sense of exactness while this value is really not guaranteed to be correct. It might have made sense in the original patch because both fields were displayed, but it does not here. Also improve the tooltip.

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Additionally, the code had to be fixed to:
- provide a proper default value for number_next_actual during creation (0 is not a valid default)
- avoid crashing during creation because the new sequence is altered before being actually created (the ir.sequence ID is used to name the sequence, so the ir.sequence record needs to be created before the PG sequence)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openerp/addons/base/ir/ir_sequence.py'
--- openerp/addons/base/ir/ir_sequence.py 2013-04-19 15:49:20 +0000
+++ openerp/addons/base/ir/ir_sequence.py 2013-05-17 15:48:24 +0000
@@ -54,6 +54,34 @@
54 """54 """
55 _name = 'ir.sequence'55 _name = 'ir.sequence'
56 _order = 'name'56 _order = 'name'
57
58 def _get_number_next_actual(self, cr, user, ids, field_name, arg, context=None):
59 '''Return number from ir_sequence row when no_gap implementation,
60 and number from postgres sequence when standard implementation.'''
61 res = dict.fromkeys(ids)
62 for element in self.browse(cr, user, ids, context=context):
63 if element.implementation != 'standard':
64 res[element.id] = element.number_next
65 else:
66 # get number from postgres sequence. Cannot use
67 # currval, because that might give an error when
68 # not having used nextval before.
69 statement = (
70 "SELECT last_value, increment_by, is_called"
71 " FROM ir_sequence_%03d"
72 % element.id)
73 cr.execute(statement)
74 (last_value, increment_by, is_called) = cr.fetchone()
75 if is_called:
76 res[element.id] = last_value + increment_by
77 else:
78 res[element.id] = last_value
79 return res
80
81 def _set_number_next_actual(self, cr, uid, id, name, value, args=None, context=None):
82 return self.write(cr, uid, id, {'number_next': value or 0}, context=context)
83
84
57 _columns = {85 _columns = {
58 'name': openerp.osv.fields.char('Name', size=64, required=True),86 'name': openerp.osv.fields.char('Name', size=64, required=True),
59 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64),87 'code': openerp.osv.fields.selection(_code_get, 'Code', size=64),
@@ -67,6 +95,7 @@
67 'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"),95 'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"),
68 'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"),96 'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"),
69 'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"),97 'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"),
98 'number_next_actual': openerp.osv.fields.function(_get_number_next_actual, fnct_inv=_set_number_next_actual, type='integer', required=True, string='Actual Next Number', help='Next number that will be used. Number is only informative and can differ from real number'),
70 'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"),99 'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"),
71 '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."),100 '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."),
72 'company_id': openerp.osv.fields.many2one('res.company', 'Company'),101 'company_id': openerp.osv.fields.many2one('res.company', 'Company'),
@@ -121,7 +150,7 @@
121 # object depends on it.150 # object depends on it.
122 cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names)151 cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names)
123152
124 def _alter_sequence(self, cr, id, number_increment, number_next):153 def _alter_sequence(self, cr, id, number_increment, number_next=None):
125 """ Alter a PostreSQL sequence.154 """ Alter a PostreSQL sequence.
126155
127 There is no access rights check.156 There is no access rights check.
@@ -129,9 +158,10 @@
129 if number_increment == 0:158 if number_increment == 0:
130 raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))159 raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))
131 assert isinstance(id, (int, long))160 assert isinstance(id, (int, long))
132 cr.execute("""161 statement = ("ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %d" % (id, number_increment))
133 ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s162 if number_next is not None:
134 """ % id, (number_increment, number_next))163 statement += " RESTART WITH %d" % (number_next, )
164 cr.execute(statement)
135165
136 def create(self, cr, uid, values, context=None):166 def create(self, cr, uid, values, context=None):
137 """ Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.167 """ Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.
@@ -160,7 +190,13 @@
160 n = values.get('number_next', row['number_next'])190 n = values.get('number_next', row['number_next'])
161 if row['implementation'] == 'standard':191 if row['implementation'] == 'standard':
162 if new_implementation in ('standard', None):192 if new_implementation in ('standard', None):
163 self._alter_sequence(cr, row['id'], i, n)193 # Implementation has NOT changed.
194 # Only change sequence if really requested.
195 if row['number_next'] != n:
196 self._alter_sequence(cr, row['id'], i, n)
197 else:
198 # Just in case only increment changed
199 self._alter_sequence(cr, row['id'], i)
164 else:200 else:
165 self._drop_sequence(cr, row['id'])201 self._drop_sequence(cr, row['id'])
166 else:202 else:
@@ -200,7 +236,7 @@
200 force_company = context.get('force_company')236 force_company = context.get('force_company')
201 if not force_company:237 if not force_company:
202 force_company = self.pool.get('res.users').browse(cr, uid, uid).company_id.id238 force_company = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
203 sequences = self.read(cr, uid, seq_ids, ['company_id','implementation','number_next','prefix','suffix','padding'])239 sequences = self.read(cr, uid, seq_ids, ['name','company_id','implementation','number_next','prefix','suffix','padding'])
204 preferred_sequences = [s for s in sequences if s['company_id'] and s['company_id'][0] == force_company ]240 preferred_sequences = [s for s in sequences if s['company_id'] and s['company_id'][0] == force_company ]
205 seq = preferred_sequences[0] if preferred_sequences else sequences[0]241 seq = preferred_sequences[0] if preferred_sequences else sequences[0]
206 if seq['implementation'] == 'standard':242 if seq['implementation'] == 'standard':
@@ -210,8 +246,11 @@
210 cr.execute("SELECT number_next FROM ir_sequence WHERE id=%s FOR UPDATE NOWAIT", (seq['id'],))246 cr.execute("SELECT number_next FROM ir_sequence WHERE id=%s FOR UPDATE NOWAIT", (seq['id'],))
211 cr.execute("UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s ", (seq['id'],))247 cr.execute("UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s ", (seq['id'],))
212 d = self._interpolation_dict()248 d = self._interpolation_dict()
213 interpolated_prefix = self._interpolate(seq['prefix'], d)249 try:
214 interpolated_suffix = self._interpolate(seq['suffix'], d)250 interpolated_prefix = self._interpolate(seq['prefix'], d)
251 interpolated_suffix = self._interpolate(seq['suffix'], d)
252 except ValueError:
253 raise osv.except_osv(_('Warning'), _('Invalid prefix or suffix for sequence \'%s\'') % (seq.get('name')))
215 return interpolated_prefix + '%%0%sd' % seq['padding'] % seq['number_next'] + interpolated_suffix254 return interpolated_prefix + '%%0%sd' % seq['padding'] % seq['number_next'] + interpolated_suffix
216255
217 def next_by_id(self, cr, uid, sequence_id, context=None):256 def next_by_id(self, cr, uid, sequence_id, context=None):
218257
=== modified file 'openerp/addons/base/ir/ir_sequence_view.xml'
--- openerp/addons/base/ir/ir_sequence_view.xml 2012-10-13 12:09:24 +0000
+++ openerp/addons/base/ir/ir_sequence_view.xml 2013-05-17 15:48:24 +0000
@@ -20,7 +20,7 @@
20 <field name="suffix"/>20 <field name="suffix"/>
21 <field name="padding"/>21 <field name="padding"/>
22 <field name="number_increment"/>22 <field name="number_increment"/>
23 <field name="number_next"/>23 <field name="number_next_actual"/>
24 <field name="implementation"/>24 <field name="implementation"/>
25 </group>25 </group>
26 <group col="3" string="Legend (for prefix, suffix)">26 <group col="3" string="Legend (for prefix, suffix)">
@@ -57,7 +57,7 @@
57 <field name="prefix"/>57 <field name="prefix"/>
58 <field name="padding"/>58 <field name="padding"/>
59 <field name="company_id" groups="base.group_multi_company"/>59 <field name="company_id" groups="base.group_multi_company"/>
60 <field name="number_next"/>60 <field name="number_next_actual"/>
61 <field name="number_increment"/>61 <field name="number_increment"/>
62 <field name="implementation"/>62 <field name="implementation"/>
63 </tree>63 </tree>