diff --git a/partner_revision/models/res_partner.py b/partner_revision/models/res_partner.py
index c3ca31e3d..0e415b05e 100644
--- a/partner_revision/models/res_partner.py
+++ b/partner_revision/models/res_partner.py
@@ -35,6 +35,12 @@ class ResPartner(models.Model):
def _add_revision(self, values):
""" Add a revision on a partner
+ By default, when a partner is modified by a user or by the
+ system, the changes are applied and a validated revision is
+ created. Callers which want to delegate the write of some
+ fields to the revision must explicitly ask for it by providing a
+ key ``__revision_rules`` in the environment's context.
+
:param values: the values being written on the partner
:type values: dict
@@ -51,8 +57,6 @@ class ResPartner(models.Model):
if not rule:
continue
if field in values:
- # TODO: if a change is done manually, values are always
- # written but we create 'done' changes
if self[field] == values[field]:
# TODO handle relations, types
continue
@@ -61,7 +65,10 @@ class ResPartner(models.Model):
'new_value': values[field],
'field_id': rule.field_id.id,
}
- if rule.default_behavior == 'auto':
+ if not self.env.context.get('__revision_rules'):
+ # by default always write on partner
+ change['state'] = 'done'
+ elif rule.default_behavior == 'auto':
change['state'] = 'done'
elif rule.default_behavior == 'validate':
change['state'] = 'draft'
diff --git a/partner_revision/tests/__init__.py b/partner_revision/tests/__init__.py
new file mode 100644
index 000000000..1f4968042
--- /dev/null
+++ b/partner_revision/tests/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import test_revision_flow
diff --git a/partner_revision/tests/common.py b/partner_revision/tests/common.py
new file mode 100644
index 000000000..f42a0240d
--- /dev/null
+++ b/partner_revision/tests/common.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+#
+#
+# Authors: Guewen Baconnier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+#
+
+
+class RevisionMixin(object):
+
+ def assert_revision(self, partner, expected_changes):
+ """ Check if a revision has been created according to expected values
+
+ The partner should have no prior revision than the one created in the
+ test (so it has exactly 1 revision).
+
+ The expected changes are tuples with (field, current_value,
+ new_value, state)
+
+ :param partner: record of partner having a revision
+ :param expected_changes: contains tuples with the changes
+ :type expected_changes: list(tuple))
+ """
+ revision = self.env['res.partner.revision'].search(
+ [('partner_id', '=', partner.id)],
+ )
+ self.assertEqual(len(revision), 1,
+ "1 revision expected, got %s" % (revision,))
+ changes = revision.change_ids
+ missing = []
+ for expected_change in expected_changes:
+ for change in changes:
+ if (change.field_id, change.current_value, change.new_value,
+ change.state) == expected_change:
+ changes -= change
+ break
+ else:
+ missing.append(expected_change)
+ message = u''
+ for field, current_value, new_value, state in missing:
+ message += ("- field: '%s', current_value: '%s', "
+ "new_value: '%s', state: '%s'\n" %
+ (field.name, current_value, new_value, state))
+ for change in changes:
+ message += ("+ field: '%s', current_value: '%s', "
+ "new_value: '%s', state: '%s'\n" %
+ (change.field_id.name, change.current_value,
+ change.new_value, change.state))
+ if message:
+ raise AssertionError('Changes do not match\n\n:%s' % message)
diff --git a/partner_revision/tests/test_revision_flow.py b/partner_revision/tests/test_revision_flow.py
new file mode 100644
index 000000000..ecdb47569
--- /dev/null
+++ b/partner_revision/tests/test_revision_flow.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+#
+#
+# Authors: Guewen Baconnier
+# Copyright 2015 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+#
+
+
+from openerp.tests import common
+from .common import RevisionMixin
+
+
+class TestRevisionFlow(RevisionMixin, common.TransactionCase):
+ """ Check how revision are generated and applied based on the rules.
+
+ We do not really care about the types of the fields in this test suite,
+ but we have to ensure that the general revision flows work as expected.
+ """
+
+ def _setup_behavior(self):
+ RevisionBehavior = self.env['revision.behavior']
+ partner_model_id = self.env.ref('base.model_res_partner').id
+ self.field_name = self.env.ref('base.field_res_partner_name')
+ self.field_street = self.env.ref('base.field_res_partner_street')
+ self.field_street2 = self.env.ref('base.field_res_partner_street2')
+ RevisionBehavior.create({
+ 'model_id': partner_model_id,
+ 'field_id': self.field_name.id,
+ 'default_behavior': 'auto',
+ })
+ RevisionBehavior.create({
+ 'model_id': partner_model_id,
+ 'field_id': self.field_street.id,
+ 'default_behavior': 'validate',
+ })
+ RevisionBehavior.create({
+ 'model_id': partner_model_id,
+ 'field_id': self.field_street2.id,
+ 'default_behavior': 'never',
+ })
+
+ def setUp(self):
+ super(TestRevisionFlow, self).setUp()
+ self._setup_behavior()
+ self.partner = self.env['res.partner'].create({
+ 'name': 'X',
+ 'street': 'street X',
+ 'street2': 'street2 X',
+ })
+
+ def assert_revision(self, partner, expected_changes):
+ """ Check if a revision has been created according to expected values
+
+ The partner should have no prior revision than the one created in the
+ test (so it has exactly 1 revision).
+
+ The expected changes are tuples with (field, current_value,
+ new_value, state)
+
+ :param partner: record of partner having a revision
+ :param expected_changes: contains tuples with the changes
+ :type expected_changes: list(tuple))
+ """
+ revision = self.env['res.partner.revision'].search(
+ [('partner_id', '=', partner.id)],
+ )
+ self.assertEqual(len(revision), 1,
+ "1 revision expected, got %s" % (revision,))
+ changes = revision.change_ids
+ missing = []
+ for expected_change in expected_changes:
+ for change in changes:
+ if (change.field_id, change.current_value, change.new_value,
+ change.state) == expected_change:
+ changes -= change
+ break
+ else:
+ missing.append(expected_change)
+ message = u''
+ for field, current_value, new_value, state in missing:
+ message += ("- field: '%s', current_value: '%s', "
+ "new_value: '%s', state: '%s'\n" %
+ (field.name, current_value, new_value, state))
+ for change in changes:
+ message += ("+ field: '%s', current_value: '%s', "
+ "new_value: '%s', state: '%s'\n" %
+ (change.field_id.name, change.current_value,
+ change.new_value, change.state))
+ if message:
+ raise AssertionError('Changes do not match\n\n:%s' % message)
+
+ def test_new_revision(self):
+ """ Add a new revision on a partner """
+ self.partner.with_context(__revision_rules=True).write({
+ 'name': 'Y',
+ 'street': 'street Y',
+ 'street2': 'street2 Y',
+ })
+ self.assert_revision(
+ self.partner,
+ [(self.field_name, 'X', 'Y', 'done'),
+ (self.field_street, 'street X', 'street Y', 'draft'),
+ (self.field_street2, 'street2 X', 'street2 Y', 'cancel'),
+ ],
+ )
+
+ def test_manual_edition(self):
+ """ A manual edition of a partner should always be applied
+
+ But should create a 'done' revision
+ """
+ self.partner.write({
+ 'name': 'Y',
+ 'street': 'street Y',
+ 'street2': 'street2 Y',
+ })
+ self.assert_revision(
+ self.partner,
+ [(self.field_name, 'X', 'Y', 'done'),
+ (self.field_street, 'street X', 'street Y', 'done'),
+ (self.field_street2, 'street2 X', 'street2 Y', 'done'),
+ ],
+ )