diff --git a/addons/membership/membership.py b/addons/membership/membership.py index 4d015c0d455..ef8eaf0eadc 100644 --- a/addons/membership/membership.py +++ b/addons/membership/membership.py @@ -413,6 +413,16 @@ class Invoice(osv.osv): member_line_obj.write(cr, uid, mlines, {'date_cancel': today}) return super(Invoice, self).action_cancel(cr, uid, ids, context=context) + # TODO master: replace by ondelete='cascade' + def unlink(self, cr, uid, ids, context=None): + member_line_obj = self.pool.get('membership.membership_line') + for invoice in self.browse(cr, uid, ids, context=context): + mlines = member_line_obj.search(cr, uid, + [('account_invoice_line', 'in', + [l.id for l in invoice.invoice_line])]) + member_line_obj.unlink(cr, uid, mlines, context=context) + return super(Invoice, self).unlink(cr, uid, ids, context=context) + class account_invoice_line(osv.osv): _inherit = 'account.invoice.line' @@ -445,6 +455,7 @@ class account_invoice_line(osv.osv): member_line_obj.unlink(cr, uid, ml_ids, context=context) return res + # TODO master: replace by ondelete='cascade' def unlink(self, cr, uid, ids, context=None): """Remove Membership Line Record for Account Invoice Line """ diff --git a/openerp/addons/base/tests/test_osv_expression.yml b/openerp/addons/base/tests/test_osv_expression.yml index 1ed07c4a8ff..33707844750 100644 --- a/openerp/addons/base/tests/test_osv_expression.yml +++ b/openerp/addons/base/tests/test_osv_expression.yml @@ -420,11 +420,19 @@ u1b = res_users.create(cr, uid, {'login': 'dbo2', 'partner_id': p1}) u2 = res_users.create(cr, uid, {'login': 'rpo', 'partner_id': p2}) assert [p1] == res_partner.search(cr, uid, [('user_ids', 'in', u1a)]), "o2m IN accept single int on right side" + assert [p1] == res_partner.search(cr, uid, [('user_ids', '=', 'Dédé Boitaclou')]), "o2m NOT IN matches none on the right side" + assert [] == res_partner.search(cr, uid, [('user_ids', 'in', [10000])]), "o2m NOT IN matches none on the right side" assert [p1,p2] == res_partner.search(cr, uid, [('user_ids', 'in', [u1a,u2])]), "o2m IN matches any on the right side" all_partners = res_partner.search(cr, uid, []) assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', u1a)])), "o2m NOT IN matches none on the right side" + # For 9.0: assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', '!=', 'Dédé Boitaclou')])), "o2m NOT IN matches none on the right side" assert (set(all_partners) - set([p1,p2])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', [u1b, u2])])), "o2m NOT IN matches none on the right side" + + + + + # child_of x returns x and its children (direct or not). company = self.browse(cr, uid, ref('ymltest_company3')) expected = [ref('ymltest_company3'), ref('ymltest_company4')] diff --git a/openerp/fields.py b/openerp/fields.py index 081e75f6fba..dbf3ebbd15e 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -44,14 +44,17 @@ def _check_value(value): def copy_cache(records, env): """ Recursively copy the cache of ``records`` to the environment ``env``. """ - for record, target in zip(records, records.with_env(env)): - if not target._cache: + todo, done = set(records), set() + while todo: + record = todo.pop() + if record not in done: + done.add(record) + target = record.with_env(env) for name, value in record._cache.iteritems(): if isinstance(value, BaseModel): - target._cache[name] = value.with_env(env) - copy_cache(value, env) - else: - target._cache[name] = value + todo.update(value) + value = value.with_env(env) + target._cache[name] = value def resolve_mro(model, name, predicate): diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 47b941485b2..196253232e3 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -985,6 +985,10 @@ class expression(object): call_null = False o2m_op = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in' push(create_substitution_leaf(leaf, ('id', o2m_op, ids1), model)) + elif operator in ('like', 'ilike', 'in', '='): + # no match found with positive search operator => no result (FALSE_LEAF) + call_null = False + push(create_substitution_leaf(leaf, FALSE_LEAF, model)) if call_null: o2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in'