diff --git a/CHANGELOG b/CHANGELOG
index 4f884f08ff..d08521d863 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Add pre-validation
* Allow to use XML file for views
* Add RPC definition
* Repace BrowseRecord by Model instance
diff --git a/doc/ref/models/models.rst b/doc/ref/models/models.rst
index 3b8614d77e..10f173cf4f 100644
--- a/doc/ref/models/models.rst
+++ b/doc/ref/models/models.rst
@@ -98,6 +98,12 @@ Class methods:
Return the definition of each field on the model.
+Instance methods:
+
+.. method:: Model.pre_validate()
+
+ This method is called by the client to validate the instance.
+
=========
ModelView
=========
diff --git a/doc/topics/views/index.rst b/doc/topics/views/index.rst
index f0b773ef40..8f6282cc74 100644
--- a/doc/topics/views/index.rst
+++ b/doc/topics/views/index.rst
@@ -118,6 +118,13 @@ List of attributes shared by many form elements:
* ``help``: The string that will be displayed when the cursor hovers over
the widget.
+ .. _common-attributes-pre_validate:
+
+ * ``pre_validate``: A boolean only for fields
+ :class:`trytond.model.fields.One2Many` to specify if the client must
+ pre-validate the records using
+ :meth:`trytond.model.Model.pre_validate`.
+
form
^^^^
@@ -216,6 +223,8 @@ Display a field of the object with the value of the current record.
* ``help``: see in common-attributes-help_.
+ * ``pre_validate``: see in common-attributes-pre_validate_.
+
image
^^^^^
@@ -471,6 +480,8 @@ field
columns that have their "expand" property set to True. Resize don't work
if this option is enabled.
+ * ``pre_validate``: see in common-attributes-pre_validate_.
+
Example
-------
diff --git a/trytond/ir/ui/form.rnc b/trytond/ir/ui/form.rnc
index ab52e0d308..d7f5f23099 100644
--- a/trytond/ir/ui/form.rnc
+++ b/trytond/ir/ui/form.rnc
@@ -101,6 +101,7 @@ attlist.field &= attribute img_width { text }?
attlist.field &= attribute img_height { text }?
attlist.field &=
[a:defaultValue = "0"] attribute filename_visible { "0" | "1" }?
+attlist.field &= [a:defaultValue = "0"] attribute pre_validate { "0" | "1" }?
image = element image { attlist.image, empty }
attlist.image &= attribute name { text }
attlist.image &= [ a:defaultValue = "1" ] attribute colspan { text }?
diff --git a/trytond/ir/ui/form.rng b/trytond/ir/ui/form.rng
index 107ac81407..823c8c3a6d 100644
--- a/trytond/ir/ui/form.rng
+++ b/trytond/ir/ui/form.rng
@@ -354,6 +354,16 @@
+
+
+
+
+ 0
+ 1
+
+
+
+
diff --git a/trytond/ir/ui/tree.rnc b/trytond/ir/ui/tree.rnc
index c52067b974..1a63112a30 100644
--- a/trytond/ir/ui/tree.rnc
+++ b/trytond/ir/ui/tree.rnc
@@ -50,6 +50,7 @@ attlist.field &=
| "top_to_bottom"
}?
attlist.field &= attribute float_time { text }?
+attlist.field &= [a:defaultValue = "0"] attribute pre_validate { "0" | "1" }?
button = element button { attlist.button, empty }
attlist.button &= attribute help { text }?
attlist.button &=
diff --git a/trytond/ir/ui/tree.rng b/trytond/ir/ui/tree.rng
index 5ecd857845..cc91f815e8 100644
--- a/trytond/ir/ui/tree.rng
+++ b/trytond/ir/ui/tree.rng
@@ -147,6 +147,16 @@
+
+
+
+
+ 0
+ 1
+
+
+
+
diff --git a/trytond/model/model.py b/trytond/model/model.py
index cc0930e135..d041675e86 100644
--- a/trytond/model/model.py
+++ b/trytond/model/model.py
@@ -53,6 +53,7 @@ class Model(WarningErrorMixin, URLMixin):
'default_get': RPC(),
'fields_get': RPC(),
'on_change_with': RPC(instantiate=0),
+ 'pre_validate': RPC(instantiate=0),
}
cls._error_messages = {}
@@ -571,6 +572,9 @@ class Model(WarningErrorMixin, URLMixin):
changes[fieldname] = getattr(self, method_name)()
return changes
+ def pre_validate(self):
+ pass
+
def __init__(self, id=None, **kwargs):
super(Model, self).__init__()
if id is not None:
diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py
index 484b37f5d9..b54d5d256e 100644
--- a/trytond/model/modelstorage.py
+++ b/trytond/model/modelstorage.py
@@ -861,6 +861,9 @@ class ModelStorage(Model):
with Transaction().set_user(Transaction().context.get('user')):
return cls._validate(cls.browse(records))
+ for record in records:
+ record.pre_validate()
+
def call(name):
method = getattr(cls, name)
if not hasattr(method, 'im_self') or method.im_self: