I agree that by signing this proposal, I - accept it on the behalf of , for an amount of + accept it on the behalf of , for an amount of with payment terms: . @@ -316,7 +316,7 @@
I agree that by paying this proposal, I - accept it on the behalf of , for an amount of + accept it on the behalf of , for an amount of with payment terms: . diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index 5c896fd956d..e645a3f5f89 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -137,7 +137,6 @@ class Product(models.Model): self.ensure_one() return self.product_tmpl_id.website_publish_button() - class ProductAttribute(models.Model): _inherit = "product.attribute" diff --git a/openerp/addons/test_new_api/tests/__init__.py b/openerp/addons/test_new_api/tests/__init__.py index 81aead1b05d..1e998327ab8 100644 --- a/openerp/addons/test_new_api/tests/__init__.py +++ b/openerp/addons/test_new_api/tests/__init__.py @@ -5,6 +5,7 @@ from . import test_new_fields from . import test_onchange from . import test_field_conversions from . import test_attributes +from . import test_one2many from . import test_ui from . import test_no_infinite_recursion from . import test_domain diff --git a/openerp/addons/test_new_api/tests/test_onchange.py b/openerp/addons/test_new_api/tests/test_onchange.py index 8516f9394e2..88e481c3052 100644 --- a/openerp/addons/test_new_api/tests/test_onchange.py +++ b/openerp/addons/test_new_api/tests/test_onchange.py @@ -176,7 +176,7 @@ class TestOnChange(common.TransactionCase): self.assertEqual(values, { 'name': partner.name, 'partner': partner.id, - 'lines': [(5,), (4, line.id)], + 'lines': [(6, 0, [line.id])], }) # modify 'partner' diff --git a/openerp/addons/test_new_api/tests/test_one2many.py b/openerp/addons/test_new_api/tests/test_one2many.py new file mode 100644 index 00000000000..38dee13ab54 --- /dev/null +++ b/openerp/addons/test_new_api/tests/test_one2many.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +from openerp.tests.common import TransactionCase + + +class One2manyCase(TransactionCase): + def setUp(self): + super(One2manyCase, self).setUp() + self.Line = self.env["test_new_api.multi.line"] + self.multi = self.env["test_new_api.multi"].create({ + "name": "What is up?" + }) + + def operations(self): + """Run operations on o2m fields to check all works fine.""" + # Check the lines first + self.assertItemsEqual( + self.multi.lines.mapped('name'), + map(str, range(10))) + # Modify the first line and drop the last one + self.multi.lines[0].name = "hello" + self.multi.lines = self.multi.lines[:-1] + self.assertEqual(len(self.multi.lines), 9) + self.assertIn("hello", self.multi.lines.mapped('name')) + # Invalidate the cache and check again; this crashes if the value + # of self.multi.lines in cache contains new records + self.multi.invalidate_cache() + self.assertEqual(len(self.multi.lines), 9) + self.assertIn("hello", self.multi.lines.mapped('name')) + + def test_new_one_by_one(self): + """Check lines created with ``new()`` and appended one by one.""" + for name in range(10): + self.multi.lines |= self.Line.new({"name": str(name)}) + self.operations() + + def test_new_single(self): + """Check lines created with ``new()`` and added in one step.""" + self.multi.lines = self.Line.browse( + [self.Line.new({"name": str(name)}).id for name in range(10)] + ) + self.operations() + + def test_create_one_by_one(self): + """Check lines created with ``create()`` and appended one by one.""" + for name in range(10): + self.multi.lines |= self.Line.create({"name": str(name)}) + self.operations() + + def test_create_single(self): + """Check lines created with ``create()`` and added in one step.""" + self.multi.lines = self.Line.browse( + [self.Line.create({"name": str(name)}).id for name in range(10)] + ) + self.operations() + + def test_rpcstyle_one_by_one(self): + """Check lines created with RPC style and appended one by one.""" + for name in range(10): + self.multi.lines = [(0, 0, {"name": str(name)})] + self.operations() + + def test_rpcstyle_single(self): + """Check lines created with RPC style and added in one step""" + self.multi.lines = [(0, 0, {'name': str(name)}) for name in range(10)] + self.operations() diff --git a/openerp/fields.py b/openerp/fields.py index 0a3e65251f4..d903097cbcb 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -868,10 +868,12 @@ class Field(object): env.invalidate(spec) else: - # simply write to the database, and update cache + # Write to database write_value = self.convert_to_write(self.convert_to_record(value, record), record) record.write({self.name: write_value}) - record._cache[self] = value + # Update the cache unless value contains a new record + if all(getattr(value, '_ids', ())): + record._cache[self] = value ############################################################################ # @@ -1836,7 +1838,7 @@ class _RelationalMulti(_Relational): def convert_to_write(self, value, record): # make result with new and existing records - result = [(5,)] + result = [(6, 0, [])] for record in value: if not record.id: values = {name: record[name] for name in record._cache} @@ -1847,7 +1849,7 @@ class _RelationalMulti(_Relational): values = record._convert_to_write(values) result.append((1, record.id, values)) else: - result.append((4, record.id)) + result[0][2].append(record.id) return result def convert_to_onchange(self, value, record, fnames=()): diff --git a/openerp/models.py b/openerp/models.py index 750849b4050..1b495d824cc 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -4008,8 +4008,7 @@ class BaseModel(object): ``(6, _, ids)`` replaces all existing records in the set by the ``ids`` list, equivalent to using the command ``5`` followed by a command - ``4`` for each ``id`` in ``ids``. Can not be used on - :class:`~openerp.fields.One2many`. + ``4`` for each ``id`` in ``ids``. .. note:: Values marked as ``_`` in the list above are ignored and can be anything, generally ``0`` or ``False``. diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index fda32b45332..87fc0032bd3 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -875,7 +875,11 @@ class one2many(_column): ids2 = act[2] or [0] cr.execute('select id from '+_table+' where '+self._fields_id+'=%s and id <> ALL (%s)', (id,ids2)) ids3 = map(lambda x:x[0], cr.fetchall()) - obj.write(cr, user, ids3, {self._fields_id:False}, context=context or {}) + inverse_field = obj._fields.get(self._fields_id) + if getattr(inverse_field, "ondelete", None) == "cascade": + obj.unlink(cr, user, ids3, context=context) + else: + obj.write(cr, user, ids3, {self._fields_id: False}, context=context or {}) return result def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):