Merge lp:~vauxoo/openobject-server/7.0_field_property_searcheable-dev-hbto into lp:openobject-server

Proposed by hbto [Vauxoo] http://www.vauxoo.com
Status: Needs review
Proposed branch: lp:~vauxoo/openobject-server/7.0_field_property_searcheable-dev-hbto
Merge into: lp:openobject-server
Diff against target: 174 lines (+150/-0) (has conflicts)
1 file modified
openerp/osv/fields.py (+150/-0)
Text conflict in openerp/osv/fields.py
To merge this branch: bzr merge lp:~vauxoo/openobject-server/7.0_field_property_searcheable-dev-hbto
Reviewer Review Type Date Requested Status
Odoo Administrators Pending
Nhomar - Vauxoo Pending
Moisés López - http://www.vauxoo.com Pending
Review via email: mp+193676@code.launchpad.net

Description of the change

This proposal tries to solve the problem that arise when trying to
look for property values on models that use them

When searching for property value all records are returned

To post a comment you must log in.

Unmerged revisions

5117. By hbto [Vauxoo] http://www.vauxoo.com

[IMP][osv][fields][property] When There is no Default Value and none record
has been set to a value, a search like [('property_field','=',False)] should
return the whole universe of values

5116. By hbto [Vauxoo] http://www.vauxoo.com

[FIX][osv][fields][property] Changed variable model in the search that
was giving wrong results, mea culpa.

Some improvements have been made to avoid unneed computes

5115. By hbto [Vauxoo] http://www.vauxoo.com

[IMP][osv][fields][property]
* Operator '!=' is working for m2o fields
This operator was obvious to add

Missing operators to develop 'Set' and 'not set'

5114. By hbto [Vauxoo] http://www.vauxoo.com

[IMP][osv][fields][property]
* Operator 'not like' is working for m2o fields
* Records that use Default values are now being taken into account (Ghost Records)

5113. By hbto [Vauxoo] http://www.vauxoo.com

[FIX] Getting rid of pdb

5112. By hbto [Vauxoo] http://www.vauxoo.com

[IMP][osv][fields]
search has been implemented for this property fields.

'char': 'value_text', #
'float': 'value_float', #
'boolean' : 'value_integer', #
'integer': 'value_integer', #
'text': 'value_text', #
'many2one': 'value_reference', #
'date' : 'value_datetime', #
'datetime' : 'value_datetime', #

5111. By hbto [Vauxoo] http://www.vauxoo.com

[IMP][fields][property] We are in the process of converting the whole
property fields from non-searchable by default to searchable by default
It is not going to be easy

It could that we have to manage with a subset of features and not all the
features available as there are for the non-functional fields

As of now, only property many2one fields are searchable, with
operator ['ilike', 'in', '=']

Default values for the property fields are not taken into account

So now it is just working for those property values that are really belonging to
the records they have been assigned.

CAUTION: With this DIFF all your Property fields will become searchable, It means
that you will be able to pick them from Advance Search, Though it does not mean
that your search it's gonna work!!!

This webservice can be usefull to make a Proof of Concept about the
workability of this DIFF

Create a DB, name it 'property', set data demo to True
Copy & Paste the code below,
Change some of the accounts of your partners to an account
different than the one as Default e.g. 'Creditors (test)' or 'Debitors (test)'
run your new webservice.

I Works!!!.

=========================================================================

#!/usr/bin/python
import oerplib
DB = 'property'
oerp = oerplib.OERP(server='localhost',database=DB,port=8069,timeout=4000)
USERS = ['admin']
PSSWS = {}.fromkeys(USERS,'admin')

for USER in USERS:
    oerp.login(user=USER, passwd=PSSWS[USER], database=DB)
    am_ids = oerp.search('res.partner',[
                           '|',
                           ('property_account_payable.type','=','payable'),
                           ('property_account_receivable.type','=','receivable'),
                           ])
    print 'AM IDS ',am_ids

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openerp/osv/fields.py'
--- openerp/osv/fields.py 2013-10-30 10:23:13 +0000
+++ openerp/osv/fields.py 2013-11-02 01:59:41 +0000
@@ -51,6 +51,9 @@
51import simplejson51import simplejson
52from openerp import SUPERUSER_ID52from openerp import SUPERUSER_ID
5353
54TERM_OPERATORS = ('=', '!=', '<=', '<', '>', '>=', '=?', '=like', '=ilike',
55 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in',
56 'child_of')
54_logger = logging.getLogger(__name__)57_logger = logging.getLogger(__name__)
5558
56def _symbol_set(symb):59def _symbol_set(symb):
@@ -1517,13 +1520,160 @@
1517 self.field_id[cr.dbname] = res and res[0]1520 self.field_id[cr.dbname] = res and res[0]
1518 return self.field_id[cr.dbname]1521 return self.field_id[cr.dbname]
15191522
1523<<<<<<< TREE
15201524
1521 def __init__(self, **args):1525 def __init__(self, **args):
1526=======
1527 def _fnct_search(self, tobj, cr, uid, obj, prop_name, args, context=None):
1528 context = context or {}
1529 prop = obj.pool.get('ir.property')
1530 # get the default values (for res_id = False) for the property fields
1531 default_val = self._get_default(obj, cr, uid, prop_name, context)
1532
1533 res = []
1534
1535 property_field = obj._all_columns.get(prop_name).column
1536 def_id = self._field_get(cr, uid, obj._name, prop_name)
1537 company = obj.pool.get('res.company')
1538 cid = company._company_default_get(cr, uid, obj._name, def_id,
1539 context=context)
1540 propdef = obj.pool.get('ir.model.fields').browse(cr, uid, def_id,
1541 context=context)
1542 from_clause = 'ir_property'
1543 where = " WHERE " + \
1544 "name = '%s' AND "% propdef.name + \
1545 "res_id like '%s,%%' AND "% obj._name + \
1546 "company_id = %s AND "% cid + \
1547 "fields_id = %s AND "% def_id + \
1548 "type = '%s'"% self._type
1549
1550 model_ids = []
1551
1552 type2field = {
1553 'char': 'value_text', #
1554 'float': 'value_float', #
1555 'boolean' : 'value_integer', #
1556 'integer': 'value_integer', #
1557 'text': 'value_text', #
1558 'binary': 'value_binary',
1559 'many2one': 'value_reference', #
1560 'date' : 'value_datetime', #
1561 'datetime' : 'value_datetime', #
1562 }
1563 ghost = False
1564 where_str = ''
1565
1566 if property_field._type == 'many2one':
1567 model_obj = obj.pool.get(property_field._obj)
1568 left, operator, right = args[0]
1569 args1 = []
1570 if operator == '!=' and right == False:
1571 args1= [(1,'=',1)]
1572 elif operator == '=' and right == False and not default_val:
1573 ghost = True
1574 elif operator in ('ilike','not ilike','=','!='):
1575 args1= [(model_obj._rec_name,operator,right)]
1576 elif operator == 'in':
1577 args1= [('id',operator,right)]
1578 #/!\ By doing this I am forgetting the possible ghosts that could match
1579 model_ids = args1 and model_obj.search(cr,uid,args1,context=context) or []
1580 if model_ids:
1581 ghost = True if default_val and default_val.id in model_ids else False
1582 #/!\ This awful query has to be got rid, a better query should arise
1583 model_ids = map(lambda x:"'%s,%s'"%(model_obj._name,x),model_ids)
1584 model_ids = ",".join(model_ids)
1585 where_str += ' AND value_reference IN (%s)'%model_ids
1586 else:
1587 #/!\ Do not return anything in case that no arguments are passed
1588 #return [('id', '=', 0)]
1589 pass
1590
1591 elif property_field._type in ('date','datetime'):
1592 left, operator, right = args[0]
1593 args1 = []
1594 type_right = (type2field.get(property_field._type),right)
1595 if operator in ('=','!=','<=','<','>','>=','=?'):
1596 where_str += " AND %s = '%s'"%type_right%operator
1597 elif operator in ('=like' '=ilike', 'like', 'not like', 'ilike', 'not ilike'):
1598 #TODO: NotImplementedYet
1599 pass
1600 elif operator in ('in', 'not in', 'child_of'):
1601 #TODO: NotImplementedYet
1602 pass
1603
1604 elif property_field._type in ('float', 'boolean', 'integer'):
1605 left, operator, right = args[0]
1606 args1 = []
1607 type_right = (type2field.get(property_field._type),right)
1608 if operator in ('=','!=','<=','<','>','>=','=?'):
1609 where_str += " AND %s %%s %d"%type_right%operator
1610 elif operator in ('=like' '=ilike', 'like', 'not like', 'ilike', 'not ilike'):
1611 #TODO: NotImplementedYet
1612 pass
1613 elif operator in ('in', 'not in', 'child_of'):
1614 #TODO: NotImplementedYet
1615 pass
1616 elif property_field._type in ('char', 'text'):
1617 left, operator, right = args[0]
1618 args1 = []
1619 type_right = (type2field.get(property_field._type),right)
1620 if operator in ('=','!=','<=','<','>','>=','=?'):
1621 where_str += " AND %s = '%s'"%type_right%operator
1622 elif operator == '=like':
1623 where_str += " AND %s =like '%s%%'"%type_right
1624 elif operator == '=ilike':
1625 where_str += " AND %s =ilike '%s%%'"%type_right
1626 elif operator == 'like':
1627 where_str += " AND %s like '%s'"%type_right
1628 elif operator == 'not like':
1629 where_str += " AND %s not like '%s'"%type_right
1630 elif operator == 'ilike':
1631 where_str += " AND %s ilike '%s'"%type_right
1632 elif operator == 'not ilike':
1633 where_str += " AND %s not ilike '%s'"%type_right
1634 elif operator in ('in', 'not in', 'child_of'):
1635 #TODO: NotImplementedYet
1636 pass
1637 ghost_ids = []
1638 if ghost:
1639 # These are all the records from obj which actually have prop_name
1640 # set as a real property_field, the other records of obj just have
1641 # a 'ghost'
1642 query = "SELECT res_id FROM %s"%from_clause + where
1643 cr.execute(query)
1644 res = cr.fetchall()
1645 res = set(res)
1646 res = map(lambda x: int(x[1]), [x[0].split(',') for x in res])
1647
1648 #This ones are the ghosts
1649 ghost_ids = obj.search(cr,uid,[('id','not in',res)],context=context)
1650
1651 res = []
1652 if where_str:
1653 query = "SELECT res_id FROM %s"%from_clause + where + where_str
1654 cr.execute(query)
1655 res = cr.fetchall()
1656 res = set(res)
1657 res = map(lambda x: int(x[1]), [x[0].split(',') for x in res])
1658
1659 res += ghost_ids
1660 if not res:
1661 return [('id', '=', 0)]
1662 return [('id', 'in', res)]
1663
1664 def __init__(self, obj_prop, **args):
1665 # TODO remove obj_prop parameter (use many2one type)
1666>>>>>>> MERGE-SOURCE
1522 self.field_id = {}1667 self.field_id = {}
1668<<<<<<< TREE
1523 if 'view_load' in args:1669 if 'view_load' in args:
1524 _logger.warning("view_load attribute is deprecated on ir.fields. Args: %r", args)1670 _logger.warning("view_load attribute is deprecated on ir.fields. Args: %r", args)
1525 obj = 'relation' in args and args['relation'] or ''1671 obj = 'relation' in args and args['relation'] or ''
1526 function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', **args)1672 function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', **args)
1673=======
1674 function.__init__(self, self._fnct_read, False, self._fnct_write,
1675 obj_prop, multi='properties',fnct_search=self._fnct_search, **args)
1676>>>>>>> MERGE-SOURCE
15271677
1528 def restart(self):1678 def restart(self):
1529 self.field_id = {}1679 self.field_id = {}