1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
25 # - relations (one2many, many2one, many2many)
29 # _classic_read: is a classic sql fields
39 from psycopg2
import Binary
45 def _symbol_set(symb
):
46 if symb
== None or symb
== False:
48 elif isinstance(symb
, unicode):
49 return symb
.encode('utf-8')
53 class _column(object):
61 _symbol_f
= _symbol_set
62 _symbol_set
= (_symbol_c
, _symbol_f
)
65 def __init__(self
, string
='unknown', required
=False, readonly
=False, domain
=None, context
='', states
=None, priority
=0, change_default
=False, size
=None, ondelete
="set null", translate
=False, select
=False, **args
):
66 self
.states
= states
or {}
68 self
.readonly
= readonly
69 self
.required
= required
71 self
.help = args
.get('help', '')
72 self
.priority
= priority
73 self
.change_default
= change_default
74 self
.ondelete
= ondelete
75 self
.translate
= translate
76 self
._domain
= domain
or []
77 self
._context
= context
84 setattr(self
, a
, args
[a
])
89 def set(self
, cr
, obj
, id, name
, value
, user
=None, context
=None):
90 cr
.execute('update '+obj
._table
+' set '+name
+'='+self
._symbol
_set
[0]+' where id=%s', (self
._symbol
_set
[1](value
), id))
92 def set_memory(self
, cr
, obj
, id, name
, value
, user
=None, context
=None):
93 raise Exception(_('Not implemented set_memory method !'))
95 def get_memory(self
, cr
, obj
, ids
, name
, user
=None, context
=None, values
=None):
96 raise Exception(_('Not implemented get_memory method !'))
98 def get(self
, cr
, obj
, ids
, name
, user
=None, offset
=0, context
=None, values
=None):
99 raise Exception(_('undefined get method !'))
101 def search(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None):
102 ids
= obj
.search(cr
, uid
, args
+self
._domain
+[(name
, 'ilike', value
)], offset
, limit
)
103 res
= obj
.read(cr
, uid
, ids
, [name
])
104 return [x
[name
] for x
in res
]
106 def search_memory(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None, context
=None):
107 raise Exception(_('Not implemented search_memory method !'))
110 # ---------------------------------------------------------
112 # ---------------------------------------------------------
113 class boolean(_column
):
116 _symbol_f
= lambda x
: x
and 'True' or 'False'
117 _symbol_set
= (_symbol_c
, _symbol_f
)
120 class integer_big(_column
):
121 _type
= 'integer_big'
123 _symbol_f
= lambda x
: int(x
or 0)
124 _symbol_set
= (_symbol_c
, _symbol_f
)
126 class integer(_column
):
129 _symbol_f
= lambda x
: int(x
or 0)
130 _symbol_set
= (_symbol_c
, _symbol_f
)
133 class reference(_column
):
136 def __init__(self
, string
, selection
, size
, **args
):
137 _column
.__init
__(self
, string
=string
, size
=size
, selection
=selection
, **args
)
143 def __init__(self
, string
, size
, **args
):
144 _column
.__init
__(self
, string
=string
, size
=size
, **args
)
145 self
._symbol
_set
= (self
._symbol
_c
, self
._symbol
_set
_char
)
147 # takes a string (encoded in utf8) and returns a string (encoded in utf8)
148 def _symbol_set_char(self
, symb
):
150 # * we need to remove the "symb==False" from the next line BUT
151 # for now too many things rely on this broken behavior
152 # * the symb==None test should be common to all data types
153 if symb
== None or symb
== False:
156 # we need to convert the string to a unicode object to be able
157 # to evaluate its length (and possibly truncate it) reliably
158 u_symb
= tools
.ustr(symb
)
160 return u_symb
[:self
.size
].encode('utf8')
168 class float(_column
):
171 _symbol_f
= lambda x
: __builtin__
.float(x
or 0.0)
172 _symbol_set
= (_symbol_c
, _symbol_f
)
174 def __init__(self
, string
='unknown', digits
=None, **args
):
175 _column
.__init
__(self
, string
=string
, **args
)
183 class datetime(_column
):
191 class binary(_column
):
194 _symbol_f
= lambda symb
: symb
and Binary(symb
) or None
195 _symbol_set
= (_symbol_c
, _symbol_f
)
196 _symbol_get
= lambda self
, x
: x
and str(x
)
198 _classic_read
= False
200 def __init__(self
, string
='unknown', filters
=None, **args
):
201 _column
.__init
__(self
, string
=string
, **args
)
202 self
.filters
= filters
204 def get_memory(self
, cr
, obj
, ids
, name
, user
=None, context
=None, values
=None):
216 if context
.get('bin_size', False) and val
:
217 res
[i
] = tools
.human_size(long(val
))
225 class selection(_column
):
228 def __init__(self
, selection
, string
='unknown', **args
):
229 _column
.__init
__(self
, string
=string
, **args
)
230 self
.selection
= selection
232 # ---------------------------------------------------------
234 # ---------------------------------------------------------
237 # Values: (0, 0, { fields }) create
238 # (1, ID, { fields }) modification
239 # (2, ID) remove (delete)
240 # (3, ID) unlink one (target id or target of relation)
242 # (5) unlink all (only valid for one2many)
244 #CHECKME: dans la pratique c'est quoi la syntaxe utilisee pour le 5? (5) ou (5, 0)?
245 class one2one(_column
):
246 _classic_read
= False
247 _classic_write
= True
250 def __init__(self
, obj
, string
='unknown', **args
):
251 warnings
.warn("The one2one field doesn't work anymore", DeprecationWarning)
252 _column
.__init
__(self
, string
=string
, **args
)
255 def set(self
, cr
, obj_src
, id, field
, act
, user
=None, context
=None):
258 obj
= obj_src
.pool
.get(self
._obj
)
259 self
._table
= obj_src
.pool
.get(self
._obj
)._table
261 id_new
= obj
.create(cr
, user
, act
[1])
262 cr
.execute('update '+obj_src
._table
+' set '+field
+'=%s where id=%s', (id_new
, id))
264 cr
.execute('select '+field
+' from '+obj_src
._table
+' where id=%s', (act
[0],))
265 id = cr
.fetchone()[0]
266 obj
.write(cr
, user
, [id], act
[1], context
=context
)
268 def search(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None):
269 return obj
.pool
.get(self
._obj
).search(cr
, uid
, args
+self
._domain
+[('name', 'like', value
)], offset
, limit
)
272 class many2one(_column
):
273 _classic_read
= False
274 _classic_write
= True
277 _symbol_f
= lambda x
: x
or None
278 _symbol_set
= (_symbol_c
, _symbol_f
)
280 def __init__(self
, obj
, string
='unknown', **args
):
281 _column
.__init
__(self
, string
=string
, **args
)
284 def set_memory(self
, cr
, obj
, id, field
, values
, user
=None, context
=None):
285 obj
.datas
.setdefault(id, {})
286 obj
.datas
[id][field
] = values
288 def get_memory(self
, cr
, obj
, ids
, name
, user
=None, context
=None, values
=None):
291 result
[id] = obj
.datas
[id][name
]
294 def get(self
, cr
, obj
, ids
, name
, user
=None, context
=None, values
=None):
301 res
[r
['id']] = r
[name
]
303 res
.setdefault(id, '')
304 obj
= obj
.pool
.get(self
._obj
)
305 # build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource}
306 from orm
import except_orm
308 names
= dict(obj
.name_get(cr
, user
, filter(None, res
.values()), context
))
311 iids
= filter(None, res
.values())
313 names
[iiid
] = '// Access Denied //'
316 if res
[r
] and res
[r
] in names
:
317 res
[r
] = (res
[r
], names
[res
[r
]])
322 def set(self
, cr
, obj_src
, id, field
, values
, user
=None, context
=None):
325 obj
= obj_src
.pool
.get(self
._obj
)
326 self
._table
= obj_src
.pool
.get(self
._obj
)._table
327 if type(values
) == type([]):
330 id_new
= obj
.create(cr
, act
[2])
331 cr
.execute('update '+obj_src
._table
+' set '+field
+'=%s where id=%s', (id_new
, id))
333 obj
.write(cr
, [act
[1]], act
[2], context
=context
)
335 cr
.execute('delete from '+self
._table
+' where id=%s', (act
[1],))
336 elif act
[0] == 3 or act
[0] == 5:
337 cr
.execute('update '+obj_src
._table
+' set '+field
+'=null where id=%s', (id,))
339 cr
.execute('update '+obj_src
._table
+' set '+field
+'=%s where id=%s', (act
[1], id))
342 cr
.execute('update '+obj_src
._table
+' set '+field
+'=%s where id=%s', (values
, id))
344 cr
.execute('update '+obj_src
._table
+' set '+field
+'=null where id=%s', (id,))
346 def search(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None):
347 return obj
.pool
.get(self
._obj
).search(cr
, uid
, args
+self
._domain
+[('name', 'like', value
)], offset
, limit
)
350 class one2many(_column
):
351 _classic_read
= False
352 _classic_write
= False
355 def __init__(self
, obj
, fields_id
, string
='unknown', limit
=None, **args
):
356 _column
.__init
__(self
, string
=string
, **args
)
358 self
._fields
_id
= fields_id
360 #one2many can't be used as condition for defaults
361 assert(self
.change_default
!= True)
363 def get_memory(self
, cr
, obj
, ids
, name
, user
=None, offset
=0, context
=None, values
=None):
367 context
= context
.copy()
368 context
.update(self
._context
)
374 ids2
= obj
.pool
.get(self
._obj
).search(cr
, user
, [(self
._fields
_id
, 'in', ids
)], limit
=self
._limit
, context
=context
)
375 for r
in obj
.pool
.get(self
._obj
).read(cr
, user
, ids2
, [self
._fields
_id
], context
=context
, load
='_classic_write'):
376 if r
[self
._fields
_id
] in res
:
377 res
[r
[self
._fields
_id
]].append(r
['id'])
380 def set_memory(self
, cr
, obj
, id, field
, values
, user
=None, context
=None):
384 context
= context
.copy()
385 context
.update(self
._context
)
388 obj
= obj
.pool
.get(self
._obj
)
391 act
[2][self
._fields
_id
] = id
392 obj
.create(cr
, user
, act
[2], context
=context
)
394 obj
.write(cr
, user
, [act
[1]], act
[2], context
=context
)
396 obj
.unlink(cr
, user
, [act
[1]], context
=context
)
398 obj
.datas
[act
[1]][self
._fields
_id
] = False
400 obj
.datas
[act
[1]] = id
402 for o
in obj
.datas
.values():
403 if o
[self
._fields
_id
] == id:
404 o
[self
._fields
_id
] = False
406 for id2
in (act
[2] or []):
407 obj
.datas
[id2
][self
._fields
_id
] = id
409 def search_memory(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None, operator
='like', context
=None):
410 raise _('Not Implemented')
412 def get(self
, cr
, obj
, ids
, name
, user
=None, offset
=0, context
=None, values
=None):
416 context
= context
.copy()
417 context
.update(self
._context
)
423 ids2
= obj
.pool
.get(self
._obj
).search(cr
, user
, [(self
._fields
_id
, 'in', ids
)], limit
=self
._limit
, context
=context
)
424 for r
in obj
.pool
.get(self
._obj
)._read
_flat
(cr
, user
, ids2
, [self
._fields
_id
], context
=context
, load
='_classic_write'):
425 res
[r
[self
._fields
_id
]].append(r
['id'])
428 def set(self
, cr
, obj
, id, field
, values
, user
=None, context
=None):
432 context
= context
.copy()
433 context
.update(self
._context
)
436 _table
= obj
.pool
.get(self
._obj
)._table
437 obj
= obj
.pool
.get(self
._obj
)
440 act
[2][self
._fields
_id
] = id
441 obj
.create(cr
, user
, act
[2], context
=context
)
443 obj
.write(cr
, user
, [act
[1]], act
[2], context
=context
)
445 obj
.unlink(cr
, user
, [act
[1]], context
=context
)
447 cr
.execute('update '+_table
+' set '+self
._fields
_id
+'=null where id=%s', (act
[1],))
449 cr
.execute('update '+_table
+' set '+self
._fields
_id
+'=%s where id=%s', (id, act
[1]))
451 cr
.execute('update '+_table
+' set '+self
._fields
_id
+'=null where '+self
._fields
_id
+'=%s', (id,))
453 obj
.write(cr
, user
, act
[2], {self
._fields
_id
:id}, context
=context
or {})
455 cr
.execute('select id from '+_table
+' where '+self
._fields
_id
+'=%s and id not in ('+','.join(map(str, ids2
))+')', (id,))
456 ids3
= map(lambda x
:x
[0], cr
.fetchall())
457 obj
.write(cr
, user
, ids3
, {self
._fields
_id
:False}, context
=context
or {})
459 def search(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None, operator
='like'):
460 return obj
.pool
.get(self
._obj
).name_search(cr
, uid
, value
, self
._domain
, offset
, limit
)
464 # Values: (0, 0, { fields }) create
465 # (1, ID, { fields }) modification
470 # (6, ?, ids) set a list of links
472 class many2many(_column
):
473 _classic_read
= False
474 _classic_write
= False
477 def __init__(self
, obj
, rel
, id1
, id2
, string
='unknown', limit
=None, **args
):
478 _column
.__init
__(self
, string
=string
, **args
)
481 raise Exception(_('The second argument of the many2many field %s must be a SQL table !'\
482 'You used %s, which is not a valid SQL table name.')% (string
,rel
))
488 def get(self
, cr
, obj
, ids
, name
, user
=None, offset
=0, context
=None, values
=None):
498 ids_s
= ','.join(map(str, ids
))
499 limit_str
= self
._limit
is not None and ' limit %d' % self
._limit
or ''
500 obj
= obj
.pool
.get(self
._obj
)
502 d1
, d2
= obj
.pool
.get('ir.rule').domain_get(cr
, user
, obj
._name
)
506 cr
.execute('SELECT '+self
._rel
+'.'+self
._id
2+','+self
._rel
+'.'+self
._id
1+' \
507 FROM '+self
._rel
+' , '+obj
._table
+' \
508 WHERE '+self
._rel
+'.'+self
._id
1+' in ('+ids_s
+') \
509 AND '+self
._rel
+'.'+self
._id
2+' = '+obj
._table
+'.id '+d1
510 +limit_str
+' order by '+obj
._table
+'.'+obj
._order
+' offset %s',
512 for r
in cr
.fetchall():
513 res
[r
[1]].append(r
[0])
516 def set(self
, cr
, obj
, id, name
, values
, user
=None, context
=None):
521 obj
= obj
.pool
.get(self
._obj
)
524 idnew
= obj
.create(cr
, user
, act
[2])
525 cr
.execute('insert into '+self
._rel
+' ('+self
._id
1+','+self
._id
2+') values (%s,%s)', (id, idnew
))
527 obj
.write(cr
, user
, [act
[1]], act
[2], context
=context
)
529 obj
.unlink(cr
, user
, [act
[1]], context
=context
)
531 cr
.execute('delete from '+self
._rel
+' where ' + self
._id
1 + '=%s and '+ self
._id
2 + '=%s', (id, act
[1]))
533 cr
.execute('insert into '+self
._rel
+' ('+self
._id
1+','+self
._id
2+') values (%s,%s)', (id, act
[1]))
535 cr
.execute('update '+self
._rel
+' set '+self
._id
2+'=null where '+self
._id
2+'=%s', (id,))
538 d1
, d2
= obj
.pool
.get('ir.rule').domain_get(cr
, user
, obj
._name
)
541 cr
.execute('delete from '+self
._rel
+' where '+self
._id
1+'=%s AND '+self
._id
2+' IN (SELECT '+self
._rel
+'.'+self
._id
2+' FROM '+self
._rel
+', '+obj
._table
+' WHERE '+self
._rel
+'.'+self
._id
1+'=%s AND '+self
._rel
+'.'+self
._id
2+' = '+obj
._table
+'.id '+ d1
+')', [id, id]+d2
)
543 for act_nbr
in act
[2]:
544 cr
.execute('insert into '+self
._rel
+' ('+self
._id
1+','+self
._id
2+') values (%s, %s)', (id, act_nbr
))
547 # TODO: use a name_search
549 def search(self
, cr
, obj
, args
, name
, value
, offset
=0, limit
=None, uid
=None, operator
='like'):
550 return obj
.pool
.get(self
._obj
).search(cr
, uid
, args
+self
._domain
+[('name', operator
, value
)], offset
, limit
)
552 def get_memory(self
, cr
, obj
, ids
, name
, user
=None, offset
=0, context
=None, values
=None):
555 result
[id] = obj
.datas
[id].get(name
, [])
558 def set_memory(self
, cr
, obj
, id, name
, values
, user
=None, context
=None):
562 # TODO: use constants instead of these magic numbers
564 raise _('Not Implemented')
566 raise _('Not Implemented')
568 raise _('Not Implemented')
570 raise _('Not Implemented')
572 raise _('Not Implemented')
574 raise _('Not Implemented')
576 obj
.datas
[id][name
] = act
[2]
579 # ---------------------------------------------------------
581 # ---------------------------------------------------------
582 class function(_column
):
583 _classic_read
= False
584 _classic_write
= False
589 # multi: compute several fields in one call
591 def __init__(self
, fnct
, arg
=None, fnct_inv
=None, fnct_inv_arg
=None, type='float', fnct_search
=None, obj
=None, method
=False, store
=False, multi
=False, **args
):
592 _column
.__init
__(self
, **args
)
594 self
._method
= method
596 self
._fnct
_inv
= fnct_inv
599 if 'relation' in args
:
600 self
._obj
= args
['relation']
601 self
._fnct
_inv
_arg
= fnct_inv_arg
605 self
._fnct
_search
= fnct_search
608 self
._classic
_read
= True
609 self
._classic
_write
= True
611 self
._symbol
_get
=lambda x
:x
and str(x
)
614 self
._symbol
_c
= float._symbol
_c
615 self
._symbol
_f
= float._symbol
_f
616 self
._symbol
_set
= float._symbol
_set
618 def search(self
, cr
, uid
, obj
, name
, args
):
619 if not self
._fnct
_search
:
620 #CHECKME: should raise an exception
622 return self
._fnct
_search
(obj
, cr
, uid
, obj
, name
, args
)
624 def get(self
, cr
, obj
, ids
, name
, user
=None, context
=None, values
=None):
631 res
= self
._fnct
(obj
, cr
, user
, ids
, name
, self
._arg
, context
)
633 res
= self
._fnct
(cr
, obj
._table
, ids
, name
, self
._arg
, context
)
635 if self
._type
== 'binary' and context
.get('bin_size', False):
636 # convert the data returned by the function with the size of that data...
637 res
= dict(map(lambda (x
, y
): (x
, tools
.human_size(len(y
or ''))), res
.items()))
641 def set(self
, cr
, obj
, id, name
, value
, user
=None, context
=None):
645 self
._fnct
_inv
(obj
, cr
, user
, id, name
, value
, self
._fnct
_inv
_arg
, context
)
648 # ---------------------------------------------------------
650 # ---------------------------------------------------------
652 class related(function
):
654 def _fnct_search(self
, tobj
, cr
, uid
, obj
=None, name
=None, domain
=None, context
={}):
655 self
._field
_get
2(cr
, uid
, obj
, context
)
659 if type(sarg
) in [type([]), type( (1,) )]:
660 where
= [(self
._arg
[i
], 'in', sarg
)]
662 where
= [(self
._arg
[i
], '=', sarg
)]
664 where
= map(lambda x
: (self
._arg
[i
],x
[1], x
[2]), domain
)
666 sarg
= obj
.pool
.get(self
._relations
[i
]['object']).search(cr
, uid
, where
, context
=context
)
668 return [(self
._arg
[0], 'in', sarg
)]
670 def _fnct_write(self
,obj
,cr
, uid
, ids
, field_name
, values
, args
, context
=None):
671 if values
and field_name
:
672 self
._field
_get
2(cr
, uid
, obj
, context
)
675 if type(ids
) != type([]):
677 objlst
= obj
.browse(cr
, uid
, ids
)
682 for i
in range(len(self
.arg
)):
683 field_detail
= self
._relations
[i
]
684 relation
= field_detail
['object']
685 if not t_data
[self
.arg
[i
]]:
688 if field_detail
['type'] in ('one2many', 'many2many'):
689 if self
._type
!= "many2one":
691 t_data
= t_data
[self
.arg
[i
]][0]
694 t_data
= t_data
[self
.arg
[i
]]
696 obj
.pool
.get(field_detail
['object']).write(cr
,uid
,[t_id
],{args
[-1]:values
})
698 def _fnct_read(self
, obj
, cr
, uid
, ids
, field_name
, args
, context
=None):
699 self
._field
_get
2(cr
, uid
, obj
, context
)
700 if not ids
: return {}
702 res
= {}.fromkeys(ids
, False)
703 objlst
= obj
.browse(cr
, uid
, ids
)
709 for i
in range(len(self
.arg
)):
710 field_detail
= self
._relations
[i
]
711 relation
= field_detail
['object']
713 if not t_data
[self
.arg
[i
]]:
719 if field_detail
['type'] in ('one2many', 'many2many'):
720 t_data
= t_data
[self
.arg
[i
]][0]
722 t_data
= t_data
[self
.arg
[i
]]
723 if type(t_data
) == type(objlst
[0]):
724 res
[data
.id] = t_data
.id
726 res
[data
.id] = t_data
728 if self
._type
=='many2one':
729 ids
= filter(None, res
.values())
731 ng
= dict(obj
.pool
.get(self
._obj
).name_get(cr
, uid
, ids
, context
=context
))
734 res
[r
] = (res
[r
], ng
[res
[r
]])
737 def __init__(self
, *arg
, **args
):
740 super(related
, self
).__init
__(self
._fnct
_read
, arg
, self
._fnct
_write
, fnct_inv_arg
=arg
, method
=True, fnct_search
=self
._fnct
_search
, **args
)
742 def _field_get2(self
, cr
, uid
, obj
, context
={}):
746 for i
in range(len(self
._arg
)):
747 f
= obj
.pool
.get(obj_name
).fields_get(cr
, uid
, [self
._arg
[i
]], context
=context
)[self
._arg
[i
]]
748 self
._relations
.append({
753 if f
.get('relation',False):
754 obj_name
= f
['relation']
755 self
._relations
[-1]['relation'] = f
['relation']
757 # ---------------------------------------------------------
759 # ---------------------------------------------------------
760 class serialized(_column
):
761 def __init__(self
, string
='unknown', serialize_func
=repr, deserialize_func
=eval, type='text', **args
):
762 self
._serialize
_func
= serialize_func
763 self
._deserialize
_func
= deserialize_func
765 self
._symbol
_set
= (self
._symbol
_c
, self
._serialize
_func
)
766 self
._symbol
_get
= self
._deserialize
_func
767 super(serialized
, self
).__init
__(string
=string
, **args
)
770 class property(function
):
772 def _fnct_write(self
, obj
, cr
, uid
, id, prop
, id_val
, val
, context
=None):
776 definition_id
= self
._field
_get
(cr
, uid
, obj
._name
, prop
)
778 property = obj
.pool
.get('ir.property')
779 nid
= property.search(cr
, uid
, [('fields_id', '=', definition_id
),
780 ('res_id', '=', obj
._name
+','+str(id))])
782 cr
.execute('DELETE FROM ir_property WHERE id=%s', (nid
.pop(),))
784 nid
= property.search(cr
, uid
, [('fields_id', '=', definition_id
),
785 ('res_id', '=', False)])
788 default_val
= property.browse(cr
, uid
, nid
[0], context
).value
790 company_id
= obj
.pool
.get('res.users').company_get(cr
, uid
, uid
)
792 newval
= (id_val
and obj_dest
+','+str(id_val
)) or False
793 if (newval
!= default_val
) and newval
:
794 propdef
= obj
.pool
.get('ir.model.fields').browse(cr
, uid
,
795 definition_id
, context
=context
)
796 res
= property.create(cr
, uid
, {
797 'name': propdef
.name
,
799 'res_id': obj
._name
+','+str(id),
800 'company_id': company_id
,
801 'fields_id': definition_id
805 def _fnct_read(self
, obj
, cr
, uid
, ids
, prop
, val
, context
=None):
808 property = obj
.pool
.get('ir.property')
809 definition_id
= self
._field
_get
(cr
, uid
, obj
._name
, prop
)
811 nid
= property.search(cr
, uid
, [('fields_id', '=', definition_id
),
812 ('res_id', '=', False)])
815 d
= property.browse(cr
, uid
, nid
[0], context
).value
816 default_val
= (d
and int(d
.split(',')[1])) or False
818 vids
= [obj
._name
+ ',' + str(id) for id in ids
]
819 nids
= property.search(cr
, uid
, [('fields_id', '=', definition_id
),
820 ('res_id', 'in', vids
)])
824 res
[id] = default_val
825 for prop
in property.browse(cr
, uid
, nids
):
826 res
[int(prop
.res_id
.split(',')[1])] = (prop
.value
and \
827 int(prop
.value
.split(',')[1])) or False
829 obj
= obj
.pool
.get(self
._obj
)
830 existing_ids
= obj
.search(cr
, uid
, [('id','in',res
.values())])
833 for res_id
in res
.values():
834 if res_id
and (res_id
not in existing_ids
):
835 if res_id
not in deleted_ids
:
836 cr
.execute('DELETE FROM ir_property WHERE value=%s', ((obj
._name
+','+str(res_id
)),))
837 deleted_ids
.append(res_id
)
838 names
= dict(obj
.name_get(cr
, uid
, filter(None, res
.values()), context
))
840 if res
[r
] and res
[r
] in names
:
841 res
[r
] = (res
[r
], names
[res
[r
]])
846 def _field_get(self
, cr
, uid
, model_name
, prop
):
847 if not self
.field_id
.get(cr
.dbname
):
848 cr
.execute('SELECT id \
849 FROM ir_model_fields \
850 WHERE name=%s AND model=%s', (prop
, model_name
))
852 self
.field_id
[cr
.dbname
] = res
and res
[0]
853 return self
.field_id
[cr
.dbname
]
855 def __init__(self
, obj_prop
, **args
):
857 function
.__init
__(self
, self
._fnct
_read
, False, self
._fnct
_write
,
858 (obj_prop
, ), **args
)
864 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: