[MERGE] point_of_sale: receipt printing reliability improvements
[odoo/odoo.git] / openerp / osv / expression.py
index 18a1e95..648a844 100644 (file)
@@ -152,8 +152,8 @@ DOMAIN_OPERATORS = (NOT_OPERATOR, OR_OPERATOR, AND_OPERATOR)
 # for consistency. This list doesn't contain '<>' as it is simpified to '!='
 # by the normalize_operator() function (so later part of the code deals with
 # only one representation).
-# An internal (i.e. not available to the user) 'inselect' operator is also
-# used. In this case its right operand has the form (subselect, params).
+# Internals (i.e. not available to the user) 'inselect' and 'not inselect'
+# operators are also used. In this case its right operand has the form (subselect, params).
 TERM_OPERATORS = ('=', '!=', '<=', '<', '>', '>=', '=?', '=like', '=ilike',
                   'like', 'not like', 'ilike', 'not ilike', 'in', 'not in',
                   'child_of')
@@ -395,7 +395,7 @@ def is_leaf(element, internal=False):
     """
     INTERNAL_OPS = TERM_OPERATORS + ('<>',)
     if internal:
-        INTERNAL_OPS += ('inselect',)
+        INTERNAL_OPS += ('inselect', 'not inselect')
     return (isinstance(element, tuple) or isinstance(element, list)) \
         and len(element) == 3 \
         and element[1] in INTERNAL_OPS \
@@ -1012,18 +1012,24 @@ class expression(object):
 
             else:
                 if field._type == 'datetime' and right and len(right) == 10:
-                    if operator in ('>', '>='):
+                    if operator in ('>', '>=', '='):
                         right += ' 00:00:00'
                     elif operator in ('<', '<='):
                         right += ' 23:59:59'
                     push(create_substitution_leaf(leaf, (left, operator, right), working_model))
 
-                elif field.translate:
+                elif field.translate and right:
                     need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
                     sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
                     if need_wildcard:
                         right = '%%%s%%' % right
 
+                    inselect_operator = 'inselect'
+                    if sql_operator in NEGATIVE_TERM_OPERATORS:
+                        # negate operator (fix lp:1071710)
+                        sql_operator = sql_operator[4:] if sql_operator[:3] == 'not' else '='
+                        inselect_operator = 'not inselect'
+
                     subselect = '( SELECT res_id'          \
                              '    FROM ir_translation'  \
                              '   WHERE name = %s'       \
@@ -1031,7 +1037,7 @@ class expression(object):
                              '     AND type = %s'
                     instr = ' %s'
                     #Covering in,not in operators with operands (%s,%s) ,etc.
-                    if sql_operator in ['in', 'not in']:
+                    if sql_operator == 'in':
                         instr = ','.join(['%s'] * len(right))
                         subselect += '     AND value ' + sql_operator + ' ' + " (" + instr + ")"   \
                              ') UNION ('                \
@@ -1051,7 +1057,7 @@ class expression(object):
                               right,
                               right,
                              ]
-                    push(create_substitution_leaf(leaf, ('id', 'inselect', (subselect, params)), working_model))
+                    push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model))
 
                 else:
                     push_result(leaf)
@@ -1072,7 +1078,7 @@ class expression(object):
         left, operator, right = leaf
 
         # final sanity checks - should never fail
-        assert operator in (TERM_OPERATORS + ('inselect',)), \
+        assert operator in (TERM_OPERATORS + ('inselect', 'not inselect')), \
             "Invalid operator %r in domain term %r" % (operator, leaf)
         assert leaf in (TRUE_LEAF, FALSE_LEAF) or left in model._all_columns \
             or left in MAGIC_COLUMNS, "Invalid field %r in domain term %r" % (left, leaf)
@@ -1091,6 +1097,10 @@ class expression(object):
             query = '(%s."%s" in (%s))' % (table_alias, left, right[0])
             params = right[1]
 
+        elif operator == 'not inselect':
+            query = '(%s."%s" not in (%s))' % (table_alias, left, right[0])
+            params = right[1]
+
         elif operator in ['in', 'not in']:
             # Two cases: right is a boolean or a list. The boolean case is an
             # abuse and handled for backward compatibility.
@@ -1114,7 +1124,9 @@ class expression(object):
                     if left == 'id':
                         instr = ','.join(['%s'] * len(params))
                     else:
-                        instr = ','.join([model._columns[left]._symbol_set[0]] * len(params))
+                        ss = model._columns[left]._symbol_set
+                        instr = ','.join([ss[0]] * len(params))
+                        params = map(ss[1], params)
                     query = '(%s."%s" %s (%s))' % (table_alias, left, operator, instr)
                 else:
                     # The case for (left, 'in', []) or (left, 'not in', []).