[Feature]: add condition to ir.sequence, let it be partitioned.

With this feature, multiple sequences may be defined per type. A weight
parameter will primarily order them. Then, the one whose condition is
true will be used.
This would let us write modules (calls to get() must be upgraded), where
the sequence numbering will depend on the data. Note that this is not
straghtforward, as the context passed must be carefully constructed. One
problem is that not all object data (eg category) may exist when the
sequence is called for a /new/ object (as a call for 'default').

The current code should be backwards compatible with old calls to get()
without a context.

bzr revid: p_christ@hol.gr-20090909203517-qahww8hika9t3zl8
This commit is contained in:
P. Christeas 2009-09-09 23:35:17 +03:00
parent 5f77353468
commit 2a16b99892
2 changed files with 30 additions and 5 deletions

View File

@ -114,6 +114,8 @@
<field name="padding"/>
<field name="number_increment"/>
<field name="number_next"/>
<field name="weight" />
<field name="condition" colspan="4" />
<separator colspan="4" string="Legend (for prefix, suffix)"/>
<group col="8" colspan="4">
<group>

View File

@ -22,6 +22,7 @@
import time
from osv import fields,osv
from tools.safe_eval import safe_eval
import pooler
class ir_sequence_type(osv.osv):
@ -47,12 +48,15 @@ class ir_sequence(osv.osv):
'number_next': fields.integer('Next Number', required=True),
'number_increment': fields.integer('Increment Number', required=True),
'padding' : fields.integer('Number padding', required=True),
'condition': fields.char('Condition', size=250, help="If set, sequence will only be used in case this python expression matches, and will precede other sequences."),
'weight': fields.integer('Weight',required=True, help="If two sequences match, the highest weight will be used.")
}
_defaults = {
'active': lambda *a: True,
'number_increment': lambda *a: 1,
'number_next': lambda *a: 1,
'padding' : lambda *a : 0,
'weight' : lambda *a: 10,
}
def _process(self, s):
@ -71,10 +75,29 @@ class ir_sequence(osv.osv):
}
def get_id(self, cr, uid, sequence_id, test='id=%s', context=None):
if not context:
context = {}
try:
cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+' AND active=%s FOR UPDATE', (sequence_id, True))
res = cr.dictfetchone()
if res:
cr.execute('SELECT id, number_next, prefix, suffix, padding, condition \
FROM ir_sequence \
WHERE '+test+' AND active=%s ORDER BY weight DESC, length(COALESCE(condition,\'\')) DESC \
FOR UPDATE', (sequence_id, True))
for res in cr.dictfetchall():
if res['condition']:
print "ir_seq: %s has condition:" %res['id'], res['condition'],
try:
bo = safe_eval(res['condition'],context)
if not bo:
print "not matched"
continue
except Exception,e:
# it would be normal to have exceptions, because
# the domain may contain errors
print "Exception.\ne:",e
print "Context:", context
continue
print "Matched!"
cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=%s', (res['id'], True))
if res['number_next']:
return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix'])
@ -84,8 +107,8 @@ class ir_sequence(osv.osv):
cr.commit()
return False
def get(self, cr, uid, code):
return self.get_id(cr, uid, code, test='code=%s')
def get(self, cr, uid, code, context = None):
return self.get_id(cr, uid, code, test='code=%s',context=context)
ir_sequence()