[tryton-debian-vcs] tryton-server branch debian updated. debian/3.8.5-1-17-g367e222

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Thu Jun 2 16:30:06 UTC 2016


The following commit has been merged in the debian branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-server.git;a=commitdiff;h=debian/3.8.5-1-17-g367e222

commit 367e222b123c0cfbb43bd58001e4e231b995de07
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Wed Jun 1 21:47:37 2016 +0200

    Releasing debian version 4.0.1-1.
    
    Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>

diff --git a/debian/changelog b/debian/changelog
index 39904c7..5b3797c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,25 @@
+tryton-server (4.0.1-1) unstable; urgency=medium
+
+  * Merging upstream version 4.0.0.
+  * Merging upstream version 4.0.1.
+  * Updating the copyright file.
+  * Updating Depends, Recommends and Suggests for 4.0.
+  * Updating and adding new manpages for the new dedicated binaries.
+  * Removing the cron option from the service file for the server.
+  * Adding a dedicated service file for the cron job.
+  * Updating README.Debian for 4.0.
+  * Updating the configuration parameters in trytond.conf.
+  * Removing the cron option from the sysvinit configuration.
+  * Providing a separate sysvinit service for the now dedicated cron job.
+  * Refreshing 01_migrate_obsolete_modules patch.
+  * Renaming 01_migrate_obsolete_modules to
+    01_migrate_obsolete_modules.patch.
+  * Adding Documentation keys to the service files.
+  * Improving the descriptions in the service files.
+  * Adding the NEWS for 4.0.
+
+ -- Mathias Behrle <mathiasb at m9s.biz>  Mon, 30 May 2016 18:17:30 +0200
+
 tryton-server (3.8.5-1) unstable; urgency=medium
 
   * Merging upstream version 3.8.5.
commit ee7e12860fd5ab0ff11b3aa08232861f3b737f98
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 18:26:05 2016 +0200

    Adding the NEWS for 4.0.

diff --git a/debian/NEWS b/debian/NEWS
index 352575d..b3d7e18 100644
--- a/debian/NEWS
+++ b/debian/NEWS
@@ -1,3 +1,23 @@
+tryton-server (4.0.1-1) unstable; urgency=medium
+
+  This is the new major release 4.0.1. It comes with major changes in the
+  configuration (namely the jsonrpc section was migrated to to a new web
+  section). You will have to adapt manually /etc/tryton/trytond.conf to
+  the changed parameters.
+  The formerly included cron job is now run by the dedicated service
+  tryton-server-cron.
+  The formerly included webdav module was separated into the separate
+  package tryton-server-webdav running its own server instance.
+
+  As for each major release don't forget to backup your database(s) and
+  then run the database update with
+  # trytond-admin --all -d <your_database_name>
+  and restart the server(s) with
+  # service tryton-server restart
+  # service tryton-server-cron restart
+
+ -- Mathias Behrle <mathiasb at m9s.biz>  Mon, 30 May 2016 18:17:30 +0200
+
 tryton-server (3.8.0-1) unstable; urgency=medium
 
   This is the new major release 3.8.0.
commit 4ee1f16f42b0e6c4dd10f79967bf6d6aba0773d2
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 16:17:02 2016 +0200

    Improving the descriptions in the service files.

diff --git a/debian/tryton-server-cron.service b/debian/tryton-server-cron.service
index ab930c2..a1187c2 100644
--- a/debian/tryton-server-cron.service
+++ b/debian/tryton-server-cron.service
@@ -1,5 +1,5 @@
 [Unit]
-Description=Tryton Application Platform Server
+Description=Tryton Server Cron
 Documentation=man:trytond-cron,file:/usr/share/doc/tryton-server,file:/usr/share/doc/tryton-server-doc,http:doc/tryton.org/
 After=remote-fs.target
 After=network.target
diff --git a/debian/tryton-server.service b/debian/tryton-server.service
index f079c99..3fb786b 100644
--- a/debian/tryton-server.service
+++ b/debian/tryton-server.service
@@ -1,5 +1,5 @@
 [Unit]
-Description=Tryton Application Platform Server
+Description=Tryton Server WSGI App
 Documentation=man:trytond,file:/usr/share/doc/tryton-server,file:/usr/share/doc/tryton-server-doc,http:doc/tryton.org/
 After=remote-fs.target
 After=network.target
commit b925c657049678d16c98b6808e16c197771fdbf6
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 16:15:32 2016 +0200

    Adding Documentation keys to the service files.

diff --git a/debian/tryton-server-cron.service b/debian/tryton-server-cron.service
index 211de53..ab930c2 100644
--- a/debian/tryton-server-cron.service
+++ b/debian/tryton-server-cron.service
@@ -1,5 +1,6 @@
 [Unit]
 Description=Tryton Application Platform Server
+Documentation=man:trytond-cron,file:/usr/share/doc/tryton-server,file:/usr/share/doc/tryton-server-doc,http:doc/tryton.org/
 After=remote-fs.target
 After=network.target
 After=postgresql.service
diff --git a/debian/tryton-server.service b/debian/tryton-server.service
index e9ce0c0..f079c99 100644
--- a/debian/tryton-server.service
+++ b/debian/tryton-server.service
@@ -1,5 +1,6 @@
 [Unit]
 Description=Tryton Application Platform Server
+Documentation=man:trytond,file:/usr/share/doc/tryton-server,file:/usr/share/doc/tryton-server-doc,http:doc/tryton.org/
 After=remote-fs.target
 After=network.target
 After=postgresql.service
commit 727715eb5fcc4a2105abeb49ebe9857121032ca9
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 15:59:33 2016 +0200

    Renaming 01_migrate_obsolete_modules to 01_migrate_obsolete_modules.patch.

diff --git a/debian/patches/01_migrate_obsolete_modules b/debian/patches/01_migrate_obsolete_modules.patch
similarity index 100%
rename from debian/patches/01_migrate_obsolete_modules
rename to debian/patches/01_migrate_obsolete_modules.patch
diff --git a/debian/patches/series b/debian/patches/series
index 8e32e7f..40b8409 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1 @@
-01_migrate_obsolete_modules
+01_migrate_obsolete_modules.patch
commit 8b0fd72b098ef7f315eb2a0997533ce27494aedf
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 15:53:36 2016 +0200

    Refreshing 01_migrate_obsolete_modules patch.

diff --git a/debian/patches/01_migrate_obsolete_modules b/debian/patches/01_migrate_obsolete_modules
index 3963664..8c4e131 100644
--- a/debian/patches/01_migrate_obsolete_modules
+++ b/debian/patches/01_migrate_obsolete_modules
@@ -8,17 +8,17 @@ Author: Mathias Behrle <mathiasb at m9s.biz>
 Bug: http://bugs.tryton.org/issue4280
 Forwarded: https://bugs.tryton.org/issue4280
 
---- tryton-server.orig/trytond/modules/__init__.py	2015-11-12 16:25:02.451033382 +0100
-+++ tryton-server/trytond/modules/__init__.py	2015-11-12 16:25:02.451033382 +0100
-@@ -378,6 +378,11 @@
-         if TableHandler.table_exist(cursor, old_table):
-             TableHandler.table_rename(cursor, old_table, new_table)
-         if update:
-+            # Migration from 2.2: module workflow removed
-+            # Migration from 3.2: module ldap_connection removed
-+            obsolete_modules = ['workflow', 'ldap_connection']
-+            cursor.execute(*ir_module.delete(
-+                    where=(ir_module.name.in_(obsolete_modules))))
-             cursor.execute(*ir_module.select(ir_module.name,
-                     where=ir_module.state.in_(('installed', 'to install',
-                             'to upgrade', 'to remove'))))
+--- tryton-server.orig/trytond/modules/__init__.py	2016-05-30 15:41:07.293541967 +0200
++++ tryton-server/trytond/modules/__init__.py	2016-05-30 15:50:17.029121049 +0200
+@@ -383,6 +383,11 @@
+             if TableHandler.table_exist(old_table):
+                 TableHandler.table_rename(old_table, new_table)
+             if update:
++                # Migration from 2.2: module workflow removed
++                # Migration from 3.2: module ldap_connection removed
++                obsolete_modules = ['workflow', 'ldap_connection']
++                cursor.execute(*ir_module.delete(
++                        where=(ir_module.name.in_(obsolete_modules))))
+                 cursor.execute(*ir_module.select(ir_module.name,
+                         where=ir_module.state.in_(('installed', 'to install',
+                                 'to upgrade', 'to remove'))))
commit 5a6a109638e12b7c922c2f7a6cfcb11652cc207e
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 13:29:35 2016 +0200

    Providing a separate sysvinit service for the now dedicated cron job.

diff --git a/debian/rules b/debian/rules
index bc555c6..aab7f26 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,7 +1,6 @@
 #!/usr/bin/make -f
 
 export PYBUILD_DESTDIR_python2=debian/tryton-server
-
 # Run tests on sqlite memory database
 # For the complete test suites refer to http://tests.tryton.org/
 export TRYTOND_DATABASE_URI=sqlite://
@@ -19,6 +18,5 @@ override_dh_auto_build:
 	sphinx-build doc build/html
 
 override_dh_installinit:
-	dh_installinit --update-rcd-params='defaults 21'
-
-
+	dh_installinit --restart-after-upgrade --name=tryton-server-cron --update-rcd-params='defaults 21'
+	dh_installinit --restart-after-upgrade --update-rcd-params='defaults 21'
diff --git a/debian/tryton-server.tryton-server-cron.init b/debian/tryton-server.tryton-server-cron.init
new file mode 100644
index 0000000..f5d44ce
--- /dev/null
+++ b/debian/tryton-server.tryton-server-cron.init
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides:             tryton-server-cron
+# Required-Start:       $syslog $remote_fs
+# Required-Stop:        $syslog $remote_fs
+# Should-Start:         $network postgresql mysql
+# Should-Stop:          $network postgresql mysql
+# Default-Start:        2 3 4 5
+# Default-Stop:         0 1 6
+# Short-Description:    Application Platform
+# Description:          Tryton is an Application Platform serving as a base for
+#                       a complete ERP software. This service runs the cron job.
+### END INIT INFO
+
+PATH="/sbin:/bin:/usr/sbin:/usr/bin"
+DAEMON="/usr/bin/trytond-cron"
+
+test -x "${DAEMON}" || exit 0
+
+BASENAME="trytond"
+NAME="${BASENAME}-cron"
+DESC="Tryton Application Platform"
+DAEMONUSER="tryton"
+PIDDIR="/var/run/${BASENAME}"
+PIDFILE="${PIDDIR}/${NAME}.pid"
+LOGCONF="/etc/tryton/${BASENAME}_log.conf"
+DEFAULTS="/etc/default/tryton-server"
+CONFIGFILE="/etc/tryton/${BASENAME}.conf"
+DAEMON_OPTS="--config ${CONFIGFILE} --logconf ${LOGCONF}"
+
+# Include tryton-server defaults if available
+if [ -r "${DEFAULTS}" ]
+then
+	. "${DEFAULTS}"
+fi
+
+. /lib/lsb/init-functions
+
+# Make sure trytond is started with configured locale
+if [ -n "${LANG}" ]
+then
+	LANG="${LANG}"
+	export LANG
+fi
+
+set -e
+
+do_start ()
+{
+	if [ ! -d "${PIDDIR}" ]
+	then
+		mkdir -p "${PIDDIR}"
+		chown "${DAEMONUSER}":"${DAEMONUSER}" "${PIDDIR}"
+	fi
+
+	start-stop-daemon --start --quiet --pidfile ${PIDFILE} \
+		--chuid ${DAEMONUSER} --background --make-pidfile \
+		--exec ${DAEMON} -- ${DAEMON_OPTS}
+}
+
+do_stop ()
+{
+	start-stop-daemon --stop --quiet --pidfile ${PIDFILE} --oknodo
+}
+
+case "${1}" in
+	start)
+		log_daemon_msg "Starting ${DESC}" "${NAME}"
+		do_start
+		log_end_msg ${?}
+		;;
+
+	stop)
+		log_daemon_msg "Stopping ${DESC}" "${NAME}"
+		do_stop
+		log_end_msg ${?}
+		;;
+
+	restart|force-reload)
+		log_daemon_msg "Restarting ${DESC}" "${NAME}"
+		do_stop
+		sleep 1
+		do_start
+		log_end_msg ${?}
+	;;
+
+	status)
+		status_of_proc -p "${PIDFILE}" "${DAEMON}" "${NAME}" && \
+		exit 0 || exit ${?}
+	;;
+
+	*)
+		N="/etc/init.d/${NAME}"
+		echo "Usage: ${N} {start|stop|restart|force-reload|status}" >&2
+		exit 1
+		;;
+esac
+
+exit 0
commit 2222ab7e02fc3979f79a35159d325ae97b36f346
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 13:23:58 2016 +0200

    Removing the cron option from the sysvinit configuration.

diff --git a/debian/tryton-server.default b/debian/tryton-server.default
index 8f8cc54..e319955 100644
--- a/debian/tryton-server.default
+++ b/debian/tryton-server.default
@@ -19,4 +19,4 @@ LOGCONF="/etc/tryton/trytond_log.conf"
 
 # Additional options that are passed to the Daemon.
 # i.e. to increase the verbosity of the server log add -v
-DAEMON_OPTS="--config ${CONFIGFILE} --logconf ${LOGCONF} --cron"
+DAEMON_OPTS="--config ${CONFIGFILE} --logconf ${LOGCONF}"
diff --git a/debian/tryton-server.init b/debian/tryton-server.init
index 765dbb3..5639c93 100644
--- a/debian/tryton-server.init
+++ b/debian/tryton-server.init
@@ -26,7 +26,7 @@ PIDFILE="${PIDDIR}/${NAME}.pid"
 LOGCONF="/etc/tryton/${NAME}_log.conf"
 DEFAULTS="/etc/default/tryton-server"
 CONFIGFILE="/etc/tryton/${NAME}.conf"
-DAEMON_OPTS="--config ${CONFIGFILE} --logconf ${LOGCONF} --cron"
+DAEMON_OPTS="--config ${CONFIGFILE} --logconf ${LOGCONF}"
 
 # Include tryton-server defaults if available
 if [ -r "${DEFAULTS}" ]
commit 52b85c6d697ab3b94e84002f14ac1d6bd6aa37ca
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 13:23:20 2016 +0200

    Updating the configuration parameters in trytond.conf.

diff --git a/debian/trytond.conf b/debian/trytond.conf
index 56f8938..a5ae51d 100644
--- a/debian/trytond.conf
+++ b/debian/trytond.conf
@@ -1,4 +1,5 @@
-# /etc/tryton/trytond.conf - Configuration file for Tryton Server (trytond)
+# /etc/tryton/trytond.conf - Configuration file for Tryton Server
+# (trytond, trytond-admin, trytond-cron)
 #
 # This file contains the most common settings for trytond (Defaults
 # are commented).
@@ -7,6 +8,25 @@
 # and accordingly
 # /usr/share/doc/tryton-server-doc/html/topics/configuration.html
 
+[web]
+# Settings for the web interface
+
+# The IP/host and port number of the interface
+# (Internal default: localhost:8000)
+#
+# Listen on all interfaces (IPv4)
+#listen = 0.0.0.0:8000
+#
+# Listen on all interfaces (IPv4 and IPv6)
+#listen = [::]:8000
+
+# The hostname for this interface
+#hostname = 
+
+# The root path to retrieve data for GET requests
+#root = /var/www/localhost/tryton
+
+
 [database]
 # Database related settings
 
@@ -52,41 +72,11 @@ path = /var/lib/tryton
 # The path to the certificate
 #certificate = /etc/ssl/certs/ssl-cert-snakeoil.pem
 
-[jsonrpc]
-# Settings for the JSON-RPC network interface
-
-# The IP/host and port number of the interface
-# (Internal default: localhost:8000)
-#
-# Listen on all interfaces (IPv4)
-#listen = 0.0.0.0:8000
-#
-# Listen on all interfaces (IPv4 and IPv6)
-#listen = [::]:8000
-
-# The hostname for this interface
-#hostname = 
-
-# The root path to retrieve data for GET requests
-#data = jsondata
-
-[xmlrpc]
-# Settings for the XML-RPC network interface
-
-# The IP/host and port number of the interface
-#listen = localhost:8069
-
-[webdav]
-# Settings for the WebDAV network interface
-
-# The IP/host and port number of the interface
-#listen = localhost:8080
-
 [session]
 # Session settings
 
 # The time (in seconds) until an inactive session expires
-#timeout = 3600
+#timeout = 600
 
 # The server administration password used by the client for
 # the execution of database management tasks. It is encrypted
@@ -117,20 +107,70 @@ path = /var/lib/tryton
 # Unoconv parameters for connection to the unoconv service.
 #unoconv = pipe,name=trytond;urp;StarOffice.ComponentContext
 
+
+# Special Settings
+
+[cache]
+# Various cache size settings.
+
+# The number of different models kept in the cache per transaction.
+#model = 200
+
+# The number of loaded records kept in the cache of the list.
+# It can be changed locally using the _record_cache_size key in Transaction.context.
+#record = 2000
+
+# The number of fields to load with eager Field.loading.
+#field = 100
+
+[table]
+# This section allows to override the default generated table names. The main purpose
+# is to bypass name length limitations of a database backend.
+# Examples:
+#account.invoice.line = acc_inv_line
+#account.invoice.tax = acc_inv_tax
+
+
 # Module settings
 #
 # Some modules are reading configuration parameters from this
 # configuration file. These settings only apply when those modules
 # are installed.
 #
-#[ldap_authentication]
-# The URI to connect to the LDAP server.
+[ldap_authentication]
+# The LDAP URL to connect to the server following RFC-2255.
 #uri = ldap://host:port/dn?attributes?scope?filter?extensions
 # A basic default URL could look like
 #uri = ldap://localhost:389/
 #
-#[product]
+# The LDAP password used to bind if needed.
+#bind_pass = 
+#
+# If the LDAP server is an Active Directory (Boolean).
+#active_directory = False
+#
+# The UID attribute for authentication.
+# (Internal default: uid)
+#uid = uid
+# If the user shall be created in the database in case it does not exist.
+# (Boolean)
+#create_user = False
+#
+[product]
 # The number of decimals with which the unit prices are stored
 # in the database. The default value is 4.
 # Warning: This setting can not be lowered once a database is created.
 #price_decimal = 4
+#
+[webdav]
+# Settings for the webdav interface
+# The IP/host and port number of the interface
+# (Internal default: localhost:8080)
+listen = localhost:8080
+# Listen on all interfaces (IPv4)
+#listen = 0.0.0.0:8080
+# Listen on all interfaces (IPv4 and IPv6)
+#listen = [::]:8080
+#
+# The hostname for this interface
+#hostname = 
commit 5db0191e781f936d968762c83c5dbf958cef23a2
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 13:07:10 2016 +0200

    Updating README.Debian for 4.0.

diff --git a/debian/tryton-server.README.Debian b/debian/tryton-server.README.Debian
index 7077d00..71a9092 100644
--- a/debian/tryton-server.README.Debian
+++ b/debian/tryton-server.README.Debian
@@ -40,14 +40,21 @@ achieve this (you need to execute all commands as root):
 Preparing the Tryton server
 ---------------------------
 
-  * Setting up the Tryton server (trytond):
+  * Setting up the Tryton server:
+
+    Note: The server comes with three binaries:
+    - trytond (runs the server(s))
+    - trytond-admin (used for the adiminstration tasks of the server, e.g. the
+      database administration)
+    - trytond-cron (runs the cron part of the server, should only be started
+      once per configuration)
 
     Adjust /etc/tryton/trytond.conf to reflect the setup of your system by using
     the database user and password from step 1 for the database URI.
 
   * If the Tryton server shall listen on some external interface (i.e. shall be
-    available for clients connecting from other machines), change the jsonrpc
-    protocol to listen accordingly.
+    available for clients connecting from other machines), change the listen
+    parameter in the web section accordingly.
 
   * If the Tryton server is listening on external interfaces, it is highly
     recommended to enable SSL for the connection.
@@ -62,6 +69,7 @@ Preparing the Tryton server
   * Restarting trytond:
 
     # service tryton-server restart
+    # service tryton-server-cron restart
 
     Note: The fingerprint of connected servers is stored in the clients
     known_hosts file. When a server is changed for its SSL usage, the client
@@ -78,6 +86,8 @@ Creating the database
 Note: The following steps can also be performed easily from the Tryton
 Client and are not mandatory to be done on the command line.
 
+From the command line:
+
   * Creating the database:
 
     # su - postgres -c "createdb --encoding=UNICODE --owner=tryton tryton"
@@ -87,7 +97,7 @@ Client and are not mandatory to be done on the command line.
 
   * Initializing the database:
 
-    # /usr/bin/trytond -c /etc/tryton/trytond.conf -u res -d tryton
+    # /usr/bin/trytond-admin -c /etc/tryton/trytond.conf -u res -d tryton
 
     Note: Use the database name you chose in the previous step (here as default: tryton).
     You will be asked for the admin password for this database.
@@ -101,7 +111,7 @@ Upgrade
     version string) you have to update your database(s).
     After the categorically recommended backup do:
 
-    # /usr/bin/trytond -c /etc/tryton/trytond.conf --all -d tryton
+    # /usr/bin/trytond-admin -c /etc/tryton/trytond.conf --all -d tryton
 
     Remember to replace tryton with the name of your database.
 
@@ -111,14 +121,8 @@ Notes
 
 Now, you're finished with the system setup. Please be aware of the following things:
 
-  * trytond has one default account for server administration:
-    - User: admin; password: the one you have configured in trytond.conf
-    as super_pwd. This user is the one used for database management tasks
-    from the client.
-
-    Note: Each Tryton database will have its own admin with login password
-    stored in the database itself (not to be confound with the admin of the
-    Tryton Server).
+  * Each Tryton database will have its own admin with login password
+    stored in the database itself.
 
   * trytond must have read access to its configuration file, otherwise it will
     start with internal defaults. The postinst script will (re)set ownership to
@@ -127,16 +131,16 @@ Now, you're finished with the system setup. Please be aware of the following thi
     means of dpkg-statoverride.
 
   * trytond listens by default on port 8000 (jsonrpc). If you need to change
-    this, edit /etc/tryton/trytond.conf in the section [jsonrpc].
+    this, edit /etc/tryton/trytond.conf in the section [web].
 
   * trytond in its upstream configuration listens by default to the localhost
     interface. If you want to change this default to listen on all interfaces,
-    edit /etc/tryton/trytond.conf in the section [jsonrpc].
+    edit /etc/tryton/trytond.conf in the section [web].
 
   * Installation of modules into the database can be done from the
     Administration Panel of the client. Under Modules you can select from the
-    modules packages (trytond-modules*) you have installed on your system.
+    modules packages (trytond-modules*) that you have installed on your system.
 
   * Only the same major version of Tryton client and Tryton server can connect.
 
- -- Mathias Behrle <mathiasb at m9s.biz>  Tue, 22 Oct 2014 16:45:00 +0200
+ -- Mathias Behrle <mathiasb at m9s.biz>  Tue, 30 May 2016 16:45:00 +0200
commit b0ef553d07badb12989532d0d2bfebe90935fa06
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 12:07:53 2016 +0200

    Adding a dedicated service file for the cron job.

diff --git a/debian/tryton-server-cron.service b/debian/tryton-server-cron.service
new file mode 100644
index 0000000..211de53
--- /dev/null
+++ b/debian/tryton-server-cron.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Tryton Application Platform Server
+After=remote-fs.target
+After=network.target
+After=postgresql.service
+After=mysql.service
+ConditionPathExists=/etc/tryton/trytond.conf
+
+[Service]
+User=tryton
+Group=tryton
+ExecStart=/usr/bin/trytond-cron --config /etc/tryton/trytond.conf --logconf /etc/tryton/trytond_log.conf
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
commit 41d7f6f249a3354bdc8b7188864567927193f0f4
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 12:07:02 2016 +0200

    Removing the cron option from the service file for the server.

diff --git a/debian/tryton-server.service b/debian/tryton-server.service
index d803fd7..e9ce0c0 100644
--- a/debian/tryton-server.service
+++ b/debian/tryton-server.service
@@ -9,7 +9,7 @@ ConditionPathExists=/etc/tryton/trytond.conf
 [Service]
 User=tryton
 Group=tryton
-ExecStart=/usr/bin/trytond --config /etc/tryton/trytond.conf --logconf /etc/tryton/trytond_log.conf --cron
+ExecStart=/usr/bin/trytond --config /etc/tryton/trytond.conf --logconf /etc/tryton/trytond_log.conf
 Restart=on-failure
 
 [Install]
commit 3b146fd7207321cd391ee2832a50f8c594981808
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Mon May 30 11:59:36 2016 +0200

    Updating and adding new manpages for the new dedicated binaries.

diff --git a/debian/manpages/trytond.1 b/debian/manpages/trytond-admin.1
similarity index 74%
copy from debian/manpages/trytond.1
copy to debian/manpages/trytond-admin.1
index cc52e6b..8daf3a8 100644
--- a/debian/manpages/trytond.1
+++ b/debian/manpages/trytond-admin.1
@@ -1,17 +1,14 @@
-.TH TRYTOND 1 "2015\-11\-12" "3.8" "Tryton Application Platform"
-
+.TH TRYTOND-ADMIN 1 "2016\-05\-30" "4.0" "Tryton Application Platform"
 .SH NAME
-trytond \- Tryton Application Platform (Server)
-
+trytond-admin \- Tryton Application Platform (Database Adminstration)
 .SH SYNOPSIS
-\fBtrytond\fR
-
+\fBtrytond-admin\fR
 .SH DESCRIPTION
 Tryton is a high-level general purpose application platform written in Python and using PostgreSQL as database engine. It is the core base of an ERP.
-
+.sp
+This script is used for the administration tasks of the server.
 .SH OPTIONS
-Usage: trytond [options]
-
+Usage: trytond-admin [options]
 .PP
 .PD 0
 .TP 20
@@ -38,32 +35,34 @@ update a module
 .TP
 .B \--all
 update all installed modules
-
+.br
 The first time a database is initialized the admin password is read from
 a file defined by the TRYTONPASSFILE environment variable or interactively asked from the user.
-The config file can be specified in the TRYTOND_CONFIG environment variable. The
-database URI can be specified in the TRYTOND_DATABASE_URI environment variable.
-
+.br
+The config file can be specified in the TRYTOND_CONFIG environment variable.
+.br
+The database URI can be specified in the TRYTOND_DATABASE_URI environment variable.
 .TP
 .B \--pidfile FILE
 file where the server pid will be stored
 .TP
 .B \--logconf FILE
 logging configuration file (ConfigParser format)
-.TP
-.B \--cron
-enable internal cron
-
+.sp
 .SH FILES
-\fB/etc/trytond.conf\fR
-
+\fB/etc/tryton/trytond.conf\fR,
+\fB/etc/tryton/trytond_log.conf\fR
+.sp
 .SH SEE ALSO
+\fItrytond\fR(1),
+\fItrytond-cron\fR(1),
 \fItryton\fR(1)
-
+.sp
 .SH HOMEPAGE
 More information about the Tryton server and the Tryton project can be found at <\fIhttp://www.tryton.org/\fR>.
-
+.sp
 .SH AUTHOR
 Tryton server was written by the Tryton project <\fIhttp://www.tryton.org/\fR>.
 .PP
 This manual page was written by Daniel Baumann <\fIdaniel at debian.org\fR> and Mathias Behrle <\fImathiasb at m9s.biz\fR>.
+
diff --git a/debian/manpages/trytond.1 b/debian/manpages/trytond-cron.1
similarity index 63%
copy from debian/manpages/trytond.1
copy to debian/manpages/trytond-cron.1
index cc52e6b..dccd53a 100644
--- a/debian/manpages/trytond.1
+++ b/debian/manpages/trytond-cron.1
@@ -1,17 +1,14 @@
-.TH TRYTOND 1 "2015\-11\-12" "3.8" "Tryton Application Platform"
-
+.TH TRYTOND-CRON 1 "2016\-05\-30" "4.0" "Tryton Application Platform"
 .SH NAME
-trytond \- Tryton Application Platform (Server)
-
+trytond-cron \- Tryton Application Platform (Cron)
 .SH SYNOPSIS
-\fBtrytond\fR
-
+\fBtrytond-cron\fR
 .SH DESCRIPTION
 Tryton is a high-level general purpose application platform written in Python and using PostgreSQL as database engine. It is the core base of an ERP.
-
+.sp
+This script runs the dedicated cron part of the server.
 .SH OPTIONS
 Usage: trytond [options]
-
 .PP
 .PD 0
 .TP 20
@@ -33,37 +30,26 @@ enable verbose mode
 .B \-d DATABASE [DATABASE ...], --database DATABASE [DATABASE ...]
 specify the database name
 .TP
-.B \-u MODULE [MODULE ...], --update MODULE [MODULE ...]
-update a module
-.TP
-.B \--all
-update all installed modules
-
-The first time a database is initialized the admin password is read from
-a file defined by the TRYTONPASSFILE environment variable or interactively asked from the user.
-The config file can be specified in the TRYTOND_CONFIG environment variable. The
-database URI can be specified in the TRYTOND_DATABASE_URI environment variable.
-
-.TP
 .B \--pidfile FILE
 file where the server pid will be stored
 .TP
 .B \--logconf FILE
 logging configuration file (ConfigParser format)
-.TP
-.B \--cron
-enable internal cron
-
+.sp
 .SH FILES
-\fB/etc/trytond.conf\fR
-
+\fB/etc/tryton/trytond.conf\fR,
+\fB/etc/tryton/trytond_log.conf\fR
+.sp
 .SH SEE ALSO
+\fItrytond\fR(1),
+\fItrytond-admin\fR(1),
 \fItryton\fR(1)
-
+.sp
 .SH HOMEPAGE
 More information about the Tryton server and the Tryton project can be found at <\fIhttp://www.tryton.org/\fR>.
-
+.sp
 .SH AUTHOR
 Tryton server was written by the Tryton project <\fIhttp://www.tryton.org/\fR>.
 .PP
 This manual page was written by Daniel Baumann <\fIdaniel at debian.org\fR> and Mathias Behrle <\fImathiasb at m9s.biz\fR>.
+
diff --git a/debian/manpages/trytond.1 b/debian/manpages/trytond.1
index cc52e6b..299fbbd 100644
--- a/debian/manpages/trytond.1
+++ b/debian/manpages/trytond.1
@@ -1,17 +1,14 @@
-.TH TRYTOND 1 "2015\-11\-12" "3.8" "Tryton Application Platform"
-
+.TH TRYTOND 1 "2016\-05\-30" "4.0" "Tryton Application Platform"
 .SH NAME
 trytond \- Tryton Application Platform (Server)
-
 .SH SYNOPSIS
 \fBtrytond\fR
-
 .SH DESCRIPTION
 Tryton is a high-level general purpose application platform written in Python and using PostgreSQL as database engine. It is the core base of an ERP.
-
+.sp
+This script runs the the server (WSGI App).
 .SH OPTIONS
 Usage: trytond [options]
-
 .PP
 .PD 0
 .TP 20
@@ -33,36 +30,24 @@ enable verbose mode
 .B \-d DATABASE [DATABASE ...], --database DATABASE [DATABASE ...]
 specify the database name
 .TP
-.B \-u MODULE [MODULE ...], --update MODULE [MODULE ...]
-update a module
-.TP
-.B \--all
-update all installed modules
-
-The first time a database is initialized the admin password is read from
-a file defined by the TRYTONPASSFILE environment variable or interactively asked from the user.
-The config file can be specified in the TRYTOND_CONFIG environment variable. The
-database URI can be specified in the TRYTOND_DATABASE_URI environment variable.
-
-.TP
 .B \--pidfile FILE
 file where the server pid will be stored
 .TP
 .B \--logconf FILE
 logging configuration file (ConfigParser format)
-.TP
-.B \--cron
-enable internal cron
-
+.sp
 .SH FILES
-\fB/etc/trytond.conf\fR
-
+\fB/etc/tryton/trytond.conf\fR,
+\fB/etc/tryton/trytond_log.conf\fR
+.sp
 .SH SEE ALSO
+\fItrytond-admin\fR(1),
+\fItrytond-cron\fR(1),
 \fItryton\fR(1)
-
+.sp
 .SH HOMEPAGE
 More information about the Tryton server and the Tryton project can be found at <\fIhttp://www.tryton.org/\fR>.
-
+.sp
 .SH AUTHOR
 Tryton server was written by the Tryton project <\fIhttp://www.tryton.org/\fR>.
 .PP
diff --git a/debian/tryton-server.links b/debian/tryton-server.links
index 9ee9859..909de8c 100644
--- a/debian/tryton-server.links
+++ b/debian/tryton-server.links
@@ -1 +1,3 @@
 /usr/share/man/man1/trytond.1.gz	/usr/share/man/man1/tryton-server.1.gz
+/usr/share/man/man1/trytond-admin.1.gz	/usr/share/man/man1/tryton-server-admin.1.gz
+/usr/share/man/man1/trytond-cron.1.gz	/usr/share/man/man1/tryton-server-cron.1.gz
commit cc57de0e082b8c953a08062a5bcf33d9331c7988
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Sat May 28 14:39:04 2016 +0200

    Updating Depends, Recommends and Suggests for 4.0.

diff --git a/debian/control b/debian/control
index 35fb51f..ca982db 100644
--- a/debian/control
+++ b/debian/control
@@ -17,6 +17,8 @@ Build-Depends:
  python-setuptools,
  python-sphinx (>= 1.0.7+dfsg),
  python-sql,
+ python-werkzeug,
+ python-wrapt,
 Standards-Version: 3.9.7
 Homepage: http://www.tryton.org/
 Vcs-Browser: https://anonscm.debian.org/cgit/tryton/tryton-server.git
@@ -34,20 +36,21 @@ Depends:
  python-polib,
  python-relatorio,
  python-sql,
+ python-werkzeug,
+ python-wrapt,
  ${misc:Depends},
  ${python:Depends},
 Recommends:
  postgresql,
- postgresql-client,
  python-bcrypt,
  python-levenshtein,
  python-psycopg2,
  python-pydot,
  python-simplejson,
- python-webdav,
  ssl-cert,
  unoconv,
 Suggests:
+ postgresql-client,
  python-sphinx,
  tryton-client | tryton-neso,
  tryton-modules-all,
commit 2d10d20a194a8d2b43fa002d070cf88a4092afed
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Fri May 27 19:01:03 2016 +0200

    Updating the copyright file.

diff --git a/debian/copyright b/debian/copyright
index c861e24..eba2cb1 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -6,6 +6,7 @@ Copyright: 2004-2008 Tiny SPRL
            2007-2013 Bertrand Chenal
            2008-2016 B2CK SPRL
            2011 Openlabs Technologies & Consulting (P) Ltd
+           2011-2016 Nicolas Évrard
 License: GPL-3+
 
 Files: doc/*
@@ -21,7 +22,7 @@ License: public-domain
 
 Files: debian/*
 Copyright: 2009-2012 Daniel Baumann <daniel at debian.org>
-           2010-2015 Mathias Behrle <mathiasb at m9s.biz>
+           2010-2016 Mathias Behrle <mathiasb at m9s.biz>
 License: GPL-3+
 
 License: GPL-3+
commit 51db7cd3c914d9caab5bd7d2c85e7903857d86a6
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Fri May 27 18:35:36 2016 +0200

    Merging upstream version 4.0.1.

diff --git a/CHANGELOG b/CHANGELOG
index 93356a4..1dfc1ed 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 4.0.1 - 2016-05-11
+* Bug fixes (see mercurial logs for details)
+
 Version 4.0.0 - 2016-05-02
 * Bug fixes (see mercurial logs for details)
 * Add sendmail module to send transactional email
diff --git a/PKG-INFO b/PKG-INFO
index ec59371..1356989 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 4.0.0
+Version: 4.0.1
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
diff --git a/doc/topics/views/index.rst b/doc/topics/views/index.rst
index 2d8e0f1..cd278c9 100644
--- a/doc/topics/views/index.rst
+++ b/doc/topics/views/index.rst
@@ -227,8 +227,6 @@ Display a field of the object with the value of the current record.
 
     * ``readonly``: Boolean to set the field readonly.
 
-    * ``required``: Boolean to set the field required.
-
     * ``mode``: Only for One2Many fields: it is a comma separated list, that
       specifies the order of the view used to display the relation. (Example:
       ``tree,form``)
@@ -514,8 +512,6 @@ field
 
     * ``readonly``: Boolean to set the field readonly.
 
-    * ``required``: Boolean to set the field required.
-
     * ``widget``: The widget that must be used instead of the default one.
 
     * ``tree_invisible``: Boolean to display or not the column.
diff --git a/trytond.egg-info/PKG-INFO b/trytond.egg-info/PKG-INFO
index ec59371..1356989 100644
--- a/trytond.egg-info/PKG-INFO
+++ b/trytond.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 4.0.0
+Version: 4.0.1
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
diff --git a/trytond/__init__.py b/trytond/__init__.py
index 44be727..54f35f5 100644
--- a/trytond/__init__.py
+++ b/trytond/__init__.py
@@ -5,7 +5,7 @@ import time
 import logging
 from email import charset
 
-__version__ = "4.0.0"
+__version__ = "4.0.1"
 logger = logging.getLogger(__name__)
 
 os.environ['TZ'] = 'UTC'
diff --git a/trytond/ir/locale/ca_ES.po b/trytond/ir/locale/ca_ES.po
index 97f96f3..33933b5 100644
--- a/trytond/ir/locale/ca_ES.po
+++ b/trytond/ir/locale/ca_ES.po
@@ -71,7 +71,6 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definició del correu electrònic sobre l'informe \"%s\", no és correcta."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
 msgstr "El nom dels adjunts ha de ser únic per recurs."
@@ -420,7 +419,7 @@ msgstr "Context"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Model del context"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1674,98 +1673,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Mòduls a actualitzar"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Data creació"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Usuari creació"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Última modificació"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Últim usuari"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Missatge"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Missatge"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Recurs"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "No llegida"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Data modificació"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Usuari modificació"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Data creació"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Usuari creació"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Usuari"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Data modificació"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Usuari modificació"
@@ -2930,7 +2913,7 @@ msgstr "Realitza instal·lacions/actualitzacions pendents"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3010,7 +2993,7 @@ msgstr "Gràfica"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Graf dels estats"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3216,11 +3199,11 @@ msgstr "Inici instal·lació/actualització mòdul"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Nota llegida"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3404,7 +3387,7 @@ msgstr "Mòduls"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3658,7 +3641,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Model"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Informe"
@@ -3805,7 +3787,7 @@ msgstr "Acció de disparador"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Executa una vegada"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3963,24 +3945,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Mòduls"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Data"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Hora"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Usuari"
diff --git a/trytond/ir/locale/de_DE.po b/trytond/ir/locale/de_DE.po
index e3eeac9..62fc2b9 100644
--- a/trytond/ir/locale/de_DE.po
+++ b/trytond/ir/locale/de_DE.po
@@ -70,7 +70,6 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Ungültige E-Mailadresse in Bericht \"%s\"."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
 msgstr ""
@@ -428,7 +427,7 @@ msgstr "Kontext"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Kontextmodell"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1072,7 +1071,7 @@ msgstr "Name"
 
 msgctxt "field:ir.cron,repeat_missed:"
 msgid "Repeat Missed"
-msgstr "Ausgelassene wiederholen"
+msgstr "Ausgelassene Aktionen nachholen"
 
 msgctxt "field:ir.cron,request_user:"
 msgid "Request User"
@@ -1682,98 +1681,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Zu aktualisierende Module"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Erstellungsdatum"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Erstellt durch"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Letzte Änderung"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Letzter Benutzer"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Nachricht"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Nachricht"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Name"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Ressource"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "Ungelesen"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Zuletzt geändert"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Letzte Änderung durch"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Erstellungsdatum"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Erstellt durch"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Notiz"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Name"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Benutzer"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Zuletzt geändert"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Letzte Änderung durch"
@@ -2941,7 +2924,7 @@ msgstr "Vorgemerkte Installationen / Aktualisierungen durchführen"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notizen"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3013,15 +2996,15 @@ msgstr "Spaltenbreiten Sicht"
 
 msgctxt "model:ir.action,name:print_model_graph"
 msgid "Graph"
-msgstr "Diagramm"
+msgstr "Graph"
 
 msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
-msgstr "Diagramm"
+msgstr "Graph"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Workflow Graph"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3227,11 +3210,11 @@ msgstr "Modulinstallation Aktualisierung Start"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Notiz"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Notiz gelesen"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3415,7 +3398,7 @@ msgstr "Module"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notizen"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3669,7 +3652,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modell"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Bericht"
@@ -3688,7 +3670,7 @@ msgstr "Wizardknopf"
 
 msgctxt "selection:ir.ui.menu,action:"
 msgid ""
-msgstr ""
+msgstr " "
 
 msgctxt "selection:ir.ui.menu,action:"
 msgid "ir.action.act_window"
@@ -3708,7 +3690,7 @@ msgstr "ir.action.wizard"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid ""
-msgstr ""
+msgstr " "
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Board"
@@ -3816,7 +3798,7 @@ msgstr "Auszuführende Aktion"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Einmalig durchführen"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3972,24 +3954,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Module"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Datum"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Notiz"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notizen"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Zeit"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Benutzer"
diff --git a/trytond/ir/locale/es_AR.po b/trytond/ir/locale/es_AR.po
index a123811..44a20ce 100644
--- a/trytond/ir/locale/es_AR.po
+++ b/trytond/ir/locale/es_AR.po
@@ -70,10 +70,9 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definición de correo electrónico en el informe «%s» no es correcta."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
-msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
+msgstr "Los nombres de los archivos adjuntos deben ser únicos por recurso."
 
 msgctxt "error:ir.cron:"
 msgid "Scheduled action failed"
@@ -425,7 +424,7 @@ msgstr "Valor del contexto"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Modelo del contexto"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1679,98 +1678,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Usuario creación"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Última Modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Último Usuario"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Recurso"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "Sin leer"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Fecha modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Usuario modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Usuario creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Fecha modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Usuario modificación"
@@ -2937,7 +2920,7 @@ msgstr "Realizar instalaciones/actualizaciones pendientes"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3017,7 +3000,7 @@ msgstr "Gráfico"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Gráfico de estados"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3223,11 +3206,11 @@ msgstr "Iniciar la instalación o actualizaciones de módulos"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Nota leída"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3411,7 +3394,7 @@ msgstr "Módulos"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3665,7 +3648,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Informe"
@@ -3812,7 +3794,7 @@ msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Ejecutar una vez"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3970,24 +3952,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Fecha"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Hora"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Usuario"
diff --git a/trytond/ir/locale/es_CO.po b/trytond/ir/locale/es_CO.po
index c6e6b48..5df5118 100644
--- a/trytond/ir/locale/es_CO.po
+++ b/trytond/ir/locale/es_CO.po
@@ -70,10 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "El correo electronico definido en el informe \"%s\" es inválido."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
-msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
+msgstr "Los nombres de los archivos adjuntos deben ser únicos por recurso."
 
 msgctxt "error:ir.cron:"
 msgid "Scheduled action failed"
@@ -251,14 +250,13 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"Al Tiempo\" y otros son mutuamente excluyentes!"
 
-#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
-"Condición \"%(condition)s\" no es una expressión python válida en el "
-"disparador \"%s(trigger)s\"."
+"La condición \"%(condition)s\" no es una expresión PYSON válida en el "
+"disparador \"%(trigger)s\"."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -424,7 +422,7 @@ msgstr "Valor del Contexto"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Modelo Contexto"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1678,98 +1676,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Fecha de Creación"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Creado por Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Última Modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Último Usuario"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Recurso"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "No leído"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Fecha de Modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Modificado por Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Fecha de Creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Creado por Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Fecha de Modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Modificado por Usuario"
@@ -2296,7 +2278,7 @@ msgstr "Número Límite"
 
 msgctxt "field:ir.trigger,minimum_time_delay:"
 msgid "Minimum Delay"
-msgstr ""
+msgstr "Retraso Mínimo"
 
 msgctxt "field:ir.trigger,model:"
 msgid "Model"
@@ -2810,13 +2792,12 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "La regla se satisface si al menos una condición es cierta"
 
-#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
-"Una instrucción Python evaluada con el registro representado por \"self\"\n"
+"Una instrucción PYSON evaluada con el registro representado por \"self\"\n"
 "Se dispara la acción si es verdadera."
 
 msgctxt "help:ir.trigger,limit_number:"
@@ -2937,7 +2918,7 @@ msgstr "Realizar Instalaciones/Actualizaciones Pendientes"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3017,7 +2998,7 @@ msgstr "Gráfico"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Gráfico de Flujo de Trabajo"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3127,20 +3108,19 @@ msgstr "Español (Colombia)"
 
 msgctxt "model:ir.lang,name:lang_es_MX"
 msgid "Spanish (Mexico)"
-msgstr ""
+msgstr "Español (México)"
 
 msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Francés"
 
-#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr "Búlgaro"
+msgstr "Hungaro"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
-msgstr ""
+msgstr "Italiano"
 
 msgctxt "model:ir.lang,name:lang_lt"
 msgid "Lithuanian"
@@ -3152,7 +3132,7 @@ msgstr "Holandés"
 
 msgctxt "model:ir.lang,name:lang_pt_BR"
 msgid "Portuguese (Brazil)"
-msgstr ""
+msgstr "Portugues"
 
 msgctxt "model:ir.lang,name:lang_ru"
 msgid "Russian"
@@ -3225,11 +3205,11 @@ msgstr "Inicio de Asistente de Instalación del Módulo"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Leer Nota"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3413,7 +3393,7 @@ msgstr "Módulos"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3667,7 +3647,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Reporte"
@@ -3686,7 +3665,7 @@ msgstr "Botón de Asistente"
 
 msgctxt "selection:ir.ui.menu,action:"
 msgid ""
-msgstr ""
+msgstr " "
 
 msgctxt "selection:ir.ui.menu,action:"
 msgid "ir.action.act_window"
@@ -3706,7 +3685,7 @@ msgstr "ir.action.wizard"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid ""
-msgstr ""
+msgstr "Hora de Última Modificación"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Board"
@@ -3804,10 +3783,9 @@ msgctxt "view:ir.attachment:"
 msgid "Attachments"
 msgstr "Adjuntos"
 
-#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr "Última Modificación"
+msgstr "Hora de Última Modificación"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
@@ -3815,7 +3793,7 @@ msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Ejecutar Una Vez"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3897,14 +3875,13 @@ msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
 msgstr "Bienvenido al asistente de configuración del módulo!"
 
-#, fuzzy
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
 msgstr ""
-"Usted será capaz de configurar la instalación en función de los módulos que "
-"ha instalado."
+"Usted podrá configurar la instalación dependiendo de los módulos que haya "
+"instalado."
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
@@ -3974,24 +3951,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Fecha"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Hora"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Usuario"
@@ -4143,10 +4118,9 @@ msgctxt "view:ir.ui.menu:"
 msgid "Menu"
 msgstr "Menú"
 
-#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr "_Mostrar"
+msgstr "Mostrar"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
diff --git a/trytond/ir/locale/es_EC.po b/trytond/ir/locale/es_EC.po
index 58c50ed..236ab7e 100644
--- a/trytond/ir/locale/es_EC.po
+++ b/trytond/ir/locale/es_EC.po
@@ -70,7 +70,6 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "La definición de correo electrónico sobre el informe \"%s\" no es válida."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
 msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
@@ -423,7 +422,7 @@ msgstr "Valor del contexto"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Modelo del contexto"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1677,98 +1676,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Fecha de creación"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Creado por usuario"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Última modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Último usuario"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Recurso"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "No leída"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Fecha de modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Modificado por usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Fecha de creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Creado por usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Fecha de modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Modificado por usuario"
@@ -2935,7 +2918,7 @@ msgstr "Realizar instalaciones/actualizaciones pendientes"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3015,7 +2998,7 @@ msgstr "Gráfico"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Gráfico de estados"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3221,11 +3204,11 @@ msgstr "Iniciar la instalación o actualización de módulos"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Nota leída"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3409,7 +3392,7 @@ msgstr "Módulos"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3663,7 +3646,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Informe"
@@ -3810,7 +3792,7 @@ msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Ejecutar una vez"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3968,24 +3950,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Fecha"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Hora"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Usuario"
diff --git a/trytond/ir/locale/es_ES.po b/trytond/ir/locale/es_ES.po
index b07e341..50fcb7d 100644
--- a/trytond/ir/locale/es_ES.po
+++ b/trytond/ir/locale/es_ES.po
@@ -71,7 +71,6 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definición de correo electrónico sobre el informe \"%s\" no es correcta."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
 msgstr "El nombre de los adjuntos debe ser único por registro."
@@ -422,7 +421,7 @@ msgstr "Valor del contexto"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Modelo del contexto"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1676,98 +1675,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Usuario creación"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Última modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Último usuario"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Mensaje"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Recurso"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "No leída"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Fecha modificación"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Usuario modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Usuario creación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Usuario"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Fecha modificación"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Usuario modificación"
@@ -2934,7 +2917,7 @@ msgstr "Realizar instalaciones/actualizaciones pendientes"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3014,7 +2997,7 @@ msgstr "Gráfico"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Grafo de los estados"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3220,11 +3203,11 @@ msgstr "Iniciar la instalación o actualización de módulos"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Nota leída"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3408,7 +3391,7 @@ msgstr "Módulos"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3592,7 +3575,7 @@ msgstr "Para actualizar"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr "Realizado"
+msgstr "Finalizado"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
@@ -3662,7 +3645,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Informe"
@@ -3809,7 +3791,7 @@ msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Ejecutar una vez"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3966,24 +3948,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Fecha"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Nota"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notas"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Hora"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Usuario"
diff --git a/trytond/ir/locale/fr_FR.po b/trytond/ir/locale/fr_FR.po
index 04b6abf..5850e13 100644
--- a/trytond/ir/locale/fr_FR.po
+++ b/trytond/ir/locale/fr_FR.po
@@ -72,11 +72,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Définition de mail incorrecte sur le rapport « %s »."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
-msgstr ""
-"Le nom des pièces jointes doivent être unique pour une même ressource !"
+msgstr "Les noms des pièces jointes doivent être unique par ressource."
 
 msgctxt "error:ir.cron:"
 msgid "Scheduled action failed"
@@ -437,7 +435,7 @@ msgstr "Valeur du contexte"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Modèle de context"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1691,98 +1689,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Modules à mettre à jour"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Date de création"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Créé par"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Dernière modification"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Dernier utilisateur"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Message"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Message"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Ressource"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "Non-lu"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Date de mise à jour"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Mis à jour par"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Date de création"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Créé par"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Note"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Utilisateur"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Date de mise à jour"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Mis à jour par"
@@ -2949,7 +2931,7 @@ msgstr "Lancer les installations/mise à jours en attente"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3029,7 +3011,7 @@ msgstr "Graphique"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Graphique de flux de travail"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3235,11 +3217,11 @@ msgstr "Installation Mise à jour de module - Début"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Note"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Note lue"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3423,7 +3405,7 @@ msgstr "Modules"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3677,7 +3659,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modèle"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Rapport"
@@ -3824,7 +3805,7 @@ msgstr "Action à déclencher"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Lancer une fois"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3982,24 +3963,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Modules"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Date"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Note"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Notes"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Heure"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Utilisateur"
diff --git a/trytond/ir/locale/sl_SI.po b/trytond/ir/locale/sl_SI.po
index 0abc790..b0c6f87 100644
--- a/trytond/ir/locale/sl_SI.po
+++ b/trytond/ir/locale/sl_SI.po
@@ -70,7 +70,6 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Neveljavna definicija epošte na izpisu \"%s\"."
 
-#, fuzzy
 msgctxt "error:ir.attachment:"
 msgid "The names of attachments must be unique by resource."
 msgstr "Imena priponk morajo biti unikatna med resursi."
@@ -415,7 +414,7 @@ msgstr "Vrednost konteksta"
 
 msgctxt "field:ir.action.act_window,context_model:"
 msgid "Context Model"
-msgstr ""
+msgstr "Kontekstni model"
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
@@ -1443,7 +1442,7 @@ msgstr "Ime"
 
 msgctxt "field:ir.model.field,relation:"
 msgid "Model Relation"
-msgstr "Model veze"
+msgstr "Vezni model"
 
 msgctxt "field:ir.model.field,ttype:"
 msgid "Field Type"
@@ -1669,98 +1668,82 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Moduli za posodobitev"
 
-#, fuzzy
 msgctxt "field:ir.note,create_date:"
 msgid "Create Date"
 msgstr "Izdelano"
 
-#, fuzzy
 msgctxt "field:ir.note,create_uid:"
 msgid "Create User"
 msgstr "Izdelal"
 
-#, fuzzy
 msgctxt "field:ir.note,id:"
 msgid "ID"
 msgstr "ID"
 
-#, fuzzy
 msgctxt "field:ir.note,last_modification:"
 msgid "Last Modification"
 msgstr "Zadnja sprememba"
 
-#, fuzzy
 msgctxt "field:ir.note,last_user:"
 msgid "Last User"
 msgstr "Zadnji uporabnik"
 
 msgctxt "field:ir.note,message:"
 msgid "Message"
-msgstr ""
+msgstr "Sporočilo"
 
 msgctxt "field:ir.note,message_wrapped:"
 msgid "Message"
-msgstr ""
+msgstr "Sporočilo"
 
-#, fuzzy
 msgctxt "field:ir.note,rec_name:"
 msgid "Name"
-msgstr "Naziv"
+msgstr "Ime"
 
-#, fuzzy
 msgctxt "field:ir.note,resource:"
 msgid "Resource"
 msgstr "Vir"
 
 msgctxt "field:ir.note,unread:"
 msgid "Unread"
-msgstr ""
+msgstr "Neprebrano"
 
-#, fuzzy
 msgctxt "field:ir.note,write_date:"
 msgid "Write Date"
 msgstr "Zapisano"
 
-#, fuzzy
 msgctxt "field:ir.note,write_uid:"
 msgid "Write User"
 msgstr "Zapisal"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
 msgstr "Izdelano"
 
-#, fuzzy
 msgctxt "field:ir.note.read,create_uid:"
 msgid "Create User"
 msgstr "Izdelal"
 
-#, fuzzy
 msgctxt "field:ir.note.read,id:"
 msgid "ID"
 msgstr "ID"
 
 msgctxt "field:ir.note.read,note:"
 msgid "Note"
-msgstr ""
+msgstr "Zabeležka"
 
-#, fuzzy
 msgctxt "field:ir.note.read,rec_name:"
 msgid "Name"
-msgstr "Naziv"
+msgstr "Ime"
 
-#, fuzzy
 msgctxt "field:ir.note.read,user:"
 msgid "User"
 msgstr "Uporabnik"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_date:"
 msgid "Write Date"
 msgstr "Zapisano"
 
-#, fuzzy
 msgctxt "field:ir.note.read,write_uid:"
 msgid "Write User"
 msgstr "Zapisal"
@@ -2925,7 +2908,7 @@ msgstr "Namesti/nadgradi"
 
 msgctxt "model:ir.action,name:act_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Zabeležke"
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
@@ -3005,7 +2988,7 @@ msgstr "Diagram"
 
 msgctxt "model:ir.action,name:report_model_workflow_graph"
 msgid "Workflow Graph"
-msgstr ""
+msgstr "Grafa delovnega toka"
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
@@ -3211,11 +3194,11 @@ msgstr "Začetek nadgradnje modula"
 
 msgctxt "model:ir.note,name:"
 msgid "Note"
-msgstr ""
+msgstr "Zabeležka"
 
 msgctxt "model:ir.note.read,name:"
 msgid "Note Read"
-msgstr ""
+msgstr "Prebrana zabeležka"
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3399,7 +3382,7 @@ msgstr "Moduli"
 
 msgctxt "model:ir.ui.menu,name:menu_note_form"
 msgid "Notes"
-msgstr ""
+msgstr "Zabeležke"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
@@ -3506,10 +3489,6 @@ msgid "Action form"
 msgstr "Ukrep za obrazec"
 
 msgctxt "selection:ir.action.keyword,keyword:"
-msgid "Action tree"
-msgstr "Ukrep za drevesni prikaz"
-
-msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Form relate"
 msgstr "Relacija"
 
@@ -3569,7 +3548,6 @@ msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
 msgstr "Ni nameščeno"
 
-#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
 msgstr "Za namestiti"
@@ -3654,7 +3632,6 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Model"
 
-#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Report"
 msgstr "Poročilo"
@@ -3801,7 +3778,7 @@ msgstr "Sprožitev ukrepa"
 
 msgctxt "view:ir.cron:"
 msgid "Run Once"
-msgstr ""
+msgstr "Enkratni zagon"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
@@ -3957,24 +3934,22 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Moduli"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "Date"
 msgstr "Datum"
 
 msgctxt "view:ir.note:"
 msgid "Note"
-msgstr ""
+msgstr "Zabeležka"
 
 msgctxt "view:ir.note:"
 msgid "Notes"
-msgstr ""
+msgstr "Zabeležke"
 
 msgctxt "view:ir.note:"
 msgid "Time"
-msgstr ""
+msgstr "Čas"
 
-#, fuzzy
 msgctxt "view:ir.note:"
 msgid "User"
 msgstr "Uporabnik"
diff --git a/trytond/protocols/jsonrpc.py b/trytond/protocols/jsonrpc.py
index 69298ef..956d291 100644
--- a/trytond/protocols/jsonrpc.py
+++ b/trytond/protocols/jsonrpc.py
@@ -121,7 +121,10 @@ class JSONRequest(Request):
     def parsed_data(self):
         if self.parsed_content_type in self.environ.get('CONTENT_TYPE', ''):
             try:
-                return json.loads(self.decoded_data, object_hook=JSONDecoder())
+                return json.loads(
+                    self.decoded_data.decode(
+                        self.charset, self.encoding_errors),
+                    object_hook=JSONDecoder())
             except Exception:
                 raise BadRequest('Unable to read JSON request')
         else:
diff --git a/trytond/res/locale/es_CO.po b/trytond/res/locale/es_CO.po
index 3d4aec4..4a87be7 100644
--- a/trytond/res/locale/es_CO.po
+++ b/trytond/res/locale/es_CO.po
@@ -11,6 +11,8 @@ msgid ""
 "Users can not be deleted for logging purpose.\n"
 "Instead you must inactivate them."
 msgstr ""
+"Los usuarios no pueden ser borrados para impedir que se logueen.\n"
+"A cambio debe desactivarlos."
 
 msgctxt "error:res.user:"
 msgid "Wrong password!"
diff --git a/trytond/tests/test_protocols.py b/trytond/tests/test_protocols.py
index 70df424..3115846 100644
--- a/trytond/tests/test_protocols.py
+++ b/trytond/tests/test_protocols.py
@@ -6,13 +6,23 @@ import json
 import datetime
 from decimal import Decimal
 
-from trytond.protocols.jsonrpc import JSONEncoder, JSONDecoder
-from trytond.protocols.xmlrpc import client
+from trytond.protocols.jsonrpc import JSONEncoder, JSONDecoder, JSONRequest
+from trytond.protocols.xmlrpc import client, XMLRequest
 
 
 class JSONTestCase(unittest.TestCase):
     'Test JSON'
 
+    def test_json_request(self):
+        req = JSONRequest.from_values(
+            data=b'{"method": "method", "params": ["foo", "bar"]}',
+            content_type='text/json',
+            )
+        self.assertEqual(req.parsed_data,
+            {'method': 'method', 'params': ['foo', 'bar']})
+        self.assertEqual(req.method, 'method')
+        self.assertEqual(req.params, ['foo', 'bar'])
+
     def dumps_loads(self, value):
         self.assertEqual(json.loads(
                 json.dumps(value, cls=JSONEncoder),
@@ -43,6 +53,14 @@ class JSONTestCase(unittest.TestCase):
 class XMLTestCase(unittest.TestCase):
     'Test XML'
 
+    def test_xml_request(self):
+        req = XMLRequest.from_values(
+            data=b"<?xml version='1.0'?>\n<methodCall>\n<methodName>method</methodName>\n<params>\n<param>\n<value><string>foo</string></value>\n</param>\n<param>\n<value><string>bar</string></value>\n</param>\n</params>\n</methodCall>\n",
+            content_type='text/xml')
+        self.assertEqual(req.parsed_data, (('foo', 'bar'), 'method'))
+        self.assertEqual(req.method, 'method')
+        self.assertEqual(req.params, ('foo', 'bar'))
+
     def dumps_loads(self, value):
         s = client.dumps((value,))
         result, _ = client.loads(s)
commit 41f0ce3d83b61a4fcd8a7e88149824f37f8aeee6
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Fri May 27 18:26:27 2016 +0200

    Merging upstream version 4.0.0.

diff --git a/CHANGELOG b/CHANGELOG
index d28a116..93356a4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,22 +1,32 @@
-Version 3.8.5 - 2016-04-06
-* Bug fixes (see mercurial logs for details)
-
-Version 3.8.4 - 2016-03-14
+Version 4.0.0 - 2016-05-02
 * Bug fixes (see mercurial logs for details)
+* Add sendmail module to send transactional email
+* Support Two-Phase Commit in Transaction
+* Allow Report to generate text plain, XML, HTML and XHTML
+* Add workflow graph on ir.model
+* Add context model on ir.action.act_window
+* Switch to WSGI API
 * Limit the login size in LoginAttempt
-
-Version 3.8.3 - 2016-02-06
-* Bug fixes (see mercurial logs for details)
+* Remove LocalDict from tools
+* Add LRUDictTransaction
+* Follow PEP-0249 for Database, Transaction and Cursor
+* Add Python3 support
+* Make TestCase create and drop its database
+* Add with_transaction decorator for tests
+* Add note on resources
+* Add 'where' operator for xxx2many fields
 * Strip and unquote double-quote from Postgresql schema in search_path
+* Move webdav into a separate module
 * Don't read historized user when evaluating record rules as it could lead to
   past privilege escalation.
-
-Version 3.8.2 - 2016-01-11
-* Bug fixes (see mercurial logs for details)
-
-Version 3.8.1 - 2015-12-16
-* Bug fixes (see mercurial logs for details)
+* Only rebuild mptt tree if left or right values have their default values
+* Allow nested inherited view
+* Add button on cron to run once
 * Check all fields when writing a sequence of records, values (CVE-2015-0861)
+* Add view_ids on tree view
+* Add parent_of operator
+* Enforce type of inheriting view
+* Use instance context in translated descriptor of Selection
 
 Version 3.8.0 - 2015-11-02
 * Bug fixes (see mercurial logs for details)
diff --git a/COPYRIGHT b/COPYRIGHT
index 41201b2..dea0462 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -3,6 +3,7 @@ Copyright (C) 2007-2016 Cédric Krier.
 Copyright (C) 2007-2013 Bertrand Chenal.
 Copyright (C) 2008-2016 B2CK SPRL.
 Copyright (C) 2011 Openlabs Technologies & Consulting (P) Ltd.
+Copyright (C) 2011-2016 Nicolas Évrard.
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
diff --git a/MANIFEST.in b/MANIFEST.in
index 30f129b..04504c8 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -12,7 +12,6 @@ include trytond/ir/tryton.cfg
 include trytond/ir/*.xml
 include trytond/ir/view/*.xml
 include trytond/ir/locale/*.po
-include trytond/ir/module/*.xml
 include trytond/ir/ui/*.xml
 include trytond/ir/ui/*.rng
 include trytond/ir/ui/*.rnc
@@ -23,7 +22,3 @@ include trytond/res/view/*.xml
 include trytond/res/locale/*.po
 include trytond/tests/tryton.cfg
 include trytond/tests/*.xml
-include trytond/webdav/tryton.cfg
-include trytond/webdav/*.xml
-include trytond/webdav/view/*.xml
-include trytond/webdav/locale/*.po
diff --git a/PKG-INFO b/PKG-INFO
index eaae680..ec59371 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 3.8.5
+Version: 4.0.0
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
 Author-email: issue_tracker at tryton.org
 License: GPL-3
-Download-URL: http://downloads.tryton.org/3.8/
+Download-URL: http://downloads.tryton.org/4.0/
 Description: trytond
         =======
         
@@ -106,6 +106,7 @@ Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU General Public License (GPL)
 Classifier: Natural Language :: Bulgarian
 Classifier: Natural Language :: Catalan
+Classifier: Natural Language :: Chinese (Simplified)
 Classifier: Natural Language :: Czech
 Classifier: Natural Language :: Dutch
 Classifier: Natural Language :: English
@@ -119,6 +120,9 @@ Classifier: Natural Language :: Slovenian
 Classifier: Natural Language :: Spanish
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
diff --git a/bin/trytond b/bin/trytond
index 89d7b31..11b38ae 100755
--- a/bin/trytond
+++ b/bin/trytond
@@ -1,80 +1,50 @@
 #!/usr/bin/env python
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 import sys
 import os
-import argparse
+import glob
+
+from werkzeug.serving import run_simple
 
 DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
     '..', '..', 'trytond')))
 if os.path.isdir(DIR):
     sys.path.insert(0, os.path.dirname(DIR))
 
-from trytond import __version__
-from trytond import server
-
-
-def parse_commandline():
-    options = {}
-
-    parser = argparse.ArgumentParser(prog='trytond')
-
-    parser.add_argument('--version', action='version',
-        version='%(prog)s ' + __version__)
-    parser.add_argument("-c", "--config", dest="configfile", metavar='FILE',
-        default=os.environ.get('TRYTOND_CONFIG'), help="specify config file")
-    parser.add_argument('--dev', dest='dev', action='store_true',
-        help='enable development mode')
-    parser.add_argument("-v", "--verbose", action="store_true",
-        dest="verbose", help="enable verbose mode")
-
-    parser.add_argument("-d", "--database", dest="database_names", nargs='+',
-        default=[], metavar='DATABASE', help="specify the database name")
-    parser.add_argument("-u", "--update", dest="update", nargs='+', default=[],
-        metavar='MODULE', help="update a module")
-    parser.add_argument("--all", dest="update", action="append_const",
-        const="ir", help="update all installed modules")
-
-    parser.add_argument("--pidfile", dest="pidfile", metavar='FILE',
-        help="file where the server pid will be stored")
-    parser.add_argument("--logconf", dest="logconf", metavar='FILE',
-        help="logging configuration file (ConfigParser format)")
-    parser.add_argument("--cron", dest="cron", action="store_true",
-        help="enable cron")
-
-    parser.epilog = ('The first time a database is initialized admin '
-        'password is read from file defined by TRYTONPASSFILE '
-        'environment variable or interactively ask user.\n'
-        'The config file can be specified in the TRYTOND_CONFIG '
-        'environment variable.\n'
-        'The database URI can be specified in the TRYTOND_DATABASE_URI '
-        'environment variable.')
-
-    options = parser.parse_args()
-
-    if not options.database_names and options.update:
-        parser.error('Missing database option')
-    return options
-
-
-if '--profile' in sys.argv:
-    import profile
-    import pstats
-    import tempfile
-    sys.argv.remove('--profile')
-
-    options = parse_commandline()
-    statfile = tempfile.mkstemp(".stat", "trytond-")[1]
-    profile.run('server.TrytonServer(options).run()', statfile)
-    s = pstats.Stats(statfile)
-    s.sort_stats('cumulative').print_stats()
-    s.sort_stats('call').print_stats()
-    s.sort_stats('time').print_stats()
-    s.sort_stats('time')
-    s.print_callers()
-    s.print_callees()
-
-    os.remove(statfile)
-else:
-    options = parse_commandline()
-    server.TrytonServer(options).run()
+import trytond.commandline as commandline
+from trytond.config import config, split_netloc
+from trytond.application import app
+from trytond.pool import Pool
+from trytond.modules import get_module_list, get_module_info
+
+
+parser = commandline.get_parser_daemon()
+options = parser.parse_args()
+commandline.config_log(options)
+config.update_etc(options.configfile)
+
+with commandline.pidfile(options):
+    for name in options.database_names:
+        Pool(name).init()
+    hostname, port = split_netloc(config.get('web', 'listen'))
+    static_files = {
+        '/': config.get('web', 'root'),
+        }
+    certificate = config.get('ssl', 'certificate')
+    privatekey = config.get('ssl', 'privatekey')
+    if certificate or privatekey:
+        ssl_context = (certificate, privatekey)
+    else:
+        ssl_context = None
+    extra_files = [options.configfile]
+    for module in get_module_list():
+        info = get_module_info(module)
+        path = os.path.join(info['directory'], 'view', '*.xml')
+        extra_files.extend(glob.glob(path))
+    run_simple(hostname, port, app,
+        threaded=True,
+        extra_files=extra_files,
+        static_files=static_files,
+        ssl_context=ssl_context,
+        use_reloader=options.dev)
diff --git a/bin/trytond-admin b/bin/trytond-admin
new file mode 100755
index 0000000..075fe1c
--- /dev/null
+++ b/bin/trytond-admin
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import sys
+import os
+
+DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
+    '..', '..', 'trytond')))
+if os.path.isdir(DIR):
+    sys.path.insert(0, os.path.dirname(DIR))
+
+import trytond.commandline as commandline
+from trytond.config import config
+import trytond.admin as admin
+
+parser = commandline.get_parser_admin()
+options = parser.parse_args()
+config.update_etc(options.configfile)
+commandline.config_log(options)
+
+admin.run(options)
diff --git a/bin/trytond-cron b/bin/trytond-cron
new file mode 100755
index 0000000..e855d77
--- /dev/null
+++ b/bin/trytond-cron
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import sys
+import os
+import time
+
+DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
+    '..', '..', 'trytond')))
+if os.path.isdir(DIR):
+    sys.path.insert(0, os.path.dirname(DIR))
+
+import trytond.commandline as commandline
+from trytond.config import config
+import trytond.cron as cron
+
+parser = commandline.get_parser_daemon()
+options = parser.parse_args()
+config.update_etc(options.configfile)
+commandline.config_log(options)
+
+with commandline.pidfile(options):
+    while True:
+        cron.run(options)
+        time.sleep(60)
diff --git a/doc/conf.py b/doc/conf.py
index efb1eae..520e241 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -48,9 +48,9 @@ copyright = (u'2008-2011, Bertrand Chenal, Cédric Krier, Ian Wilson, '
 # built documents.
 #
 # The short X.Y version.
-version = '3.8'
+version = '4.0'
 # The full version, including alpha/beta/rc tags.
-release = '3.8'
+release = '4.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/index.rst b/doc/index.rst
index 5ee2f0d..2c72ca5 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -26,7 +26,8 @@ First steps
     * **Installation:**
       :ref:`Installation <topics-install>` |
       :ref:`Configuration <topics-configuration>` |
-      :ref:`Setup a database <topics-setup-database>`
+      :ref:`Setup a database <topics-setup-database>` |
+      :ref:`Start the server <topics-start-server>`
 
 The model layer
 ===============
diff --git a/doc/ref/index.rst b/doc/ref/index.rst
index 30ff4e0..4203034 100644
--- a/doc/ref/index.rst
+++ b/doc/ref/index.rst
@@ -14,3 +14,4 @@ API Reference
     tools/singleton
     pool
     rpc
+    sendmail
diff --git a/doc/ref/models/fields.rst b/doc/ref/models/fields.rst
index 032603e..8139c62 100644
--- a/doc/ref/models/fields.rst
+++ b/doc/ref/models/fields.rst
@@ -373,6 +373,11 @@ Binary
 
 A binary field. It will be represented in Python by a ``bytes`` instance.
 
+.. warning::
+    If the context contains a key composed of the model name and field name
+    separated by a dot and its value is the string `size` then the read value
+    is the size instead of the content.
+
 :class:`Binary` has one extra optional argument:
 
 .. attribute:: Binary.filename
@@ -404,8 +409,8 @@ A string field with limited values to choice.
     The first element in each tuple is the actual value stored. The second
     element is the human-readable name.
 
-    It can also be the name of a class method on the model, that will return an
-    appropriate list. The signature of the method is::
+    It can also be the name of a class or instance method on the model, that
+    will return an appropriate list. The signature of the method is::
 
         selection()
 
@@ -439,7 +444,8 @@ Instance methods:
 .. method:: Selection.translated([name])
 
     Returns a descriptor for the translated value of the field. The descriptor
-    must be used on the same class as the field.
+    must be used on the same class as the field. It will use the language
+    defined in the context of the instance accessed.
 
 Reference
 ---------
@@ -484,6 +490,9 @@ A many-to-one relation field.
     Tree Traversal`_.
     It only works if the :attr:`model_name` is the same then the model.
 
+.. warning:: The MPTT Tree will be rebuild on database update if one record
+    is found having left or right field value equals to the default or NULL.
+
 .. _`Modified Preorder Tree Traversal`: http://en.wikipedia.org/wiki/Tree_traversal
 
 .. attribute:: Many2One.right
diff --git a/doc/ref/pool.rst b/doc/ref/pool.rst
index 0ca5638..88f42bc 100644
--- a/doc/ref/pool.rst
+++ b/doc/ref/pool.rst
@@ -39,10 +39,15 @@ Instance methods:
 
     Return an interator over instances names.
 
-.. method:: Pool.setup(module)
+.. method:: Pool.fill(module)
 
-    Setup classes for module and return a list of classes for each type in a
-    dictionary.
+    Fill the pool with the registered class from the module and return a list
+    of classes for each type in a dictionary.
+
+.. method:: Pool.setup([classes])
+
+    Call all setup methods of the classes provided or for all the registered
+    classes.
 
 ========
 PoolMeta
diff --git a/doc/ref/sendmail.rst b/doc/ref/sendmail.rst
new file mode 100644
index 0000000..4b77b31
--- /dev/null
+++ b/doc/ref/sendmail.rst
@@ -0,0 +1,44 @@
+.. _ref-sendmail:
+.. module:: trytond.sendmail
+
+========
+Sendmail
+========
+
+.. method:: sendmail_transactional(from_addr, to_addrs, msg[, transaction[, datamanager]])
+
+Send email message only if the current transaction is successfully committed.
+The required arguments are an `RFC 822`_ from-address string, a list of `RFC
+822`_ to-address strings (a bare string will be treated as a list with 1
+address), and an email message.
+The caller may pass a :class:`Transaction` instance to join otherwise the
+current one will be joined. A specific data manager can be specified otherwise
+the default :class:`SMTPDataManager` will be used for sending email.
+
+.. warning::
+
+    An SMTP failure will be only logged without raising any exception.
+
+.. method:: sendmail(from_addr, to_addrs, msg[, server])
+
+Send email message like :meth:`sendmail_transactional` but directly without
+caring about the transaction.
+The caller may pass a server instance from `smtplib`_.
+
+.. method:: get_smtp_server([uri])
+
+Return a SMTP instance from `smtplib`_ using the `uri` or the one defined in
+the `email` section of the :ref:`configuration <topics-configuration>`.
+
+
+.. class:: SMTPDataManager([uri])
+
+A :class:`SMTPDataManager` implements a data manager which send queued email at
+commit. An option optional `uri` can be passed to configure the SMTP connection.
+
+.. method:: SMTPDataManager.put(from_addr, to_addrs, msg)
+
+    Queue the email message to send.
+
+.. _`RFC 822`: https://tools.ietf.org/html/rfc822.html
+.. _`smtplib`: https://docs.python.org/2/library/smtplib.html
diff --git a/doc/ref/transaction.rst b/doc/ref/transaction.rst
index 2ddc292..b212945 100644
--- a/doc/ref/transaction.rst
+++ b/doc/ref/transaction.rst
@@ -7,19 +7,21 @@ Transaction
 
 .. class:: Transaction
 
-This class is a `singleton`_ that contains thread-local parameters of the
-database transaction.
-
-.. _`singleton`: http://en.wikipedia.org/wiki/Singleton_pattern
+This class represents a Tryton transaction that contains thread-local
+parameters of a database connection. The Transaction instances are 
+`context manager`_ that will commit or rollback the database transaction. In
+the event of an exception the transaction is rolled back, otherwise it is
+commited.
 
+.. attribute:: Transaction.database
 
-.. attribute:: Transaction.cursor
+    The database.
 
-    The database cursor.
+.. attribute:: Transaction.readonly
 
-.. attribute:: Transaction.database
+.. attribute:: Transaction.connection
 
-    The database.
+    The database connection as defined by the `PEP-0249`_.
 
 .. attribute:: Transaction.user
 
@@ -43,14 +45,20 @@ database transaction.
 
     Count the number of modification made in this transaction.
 
+.. method:: Transaction.cursor()
+
+    Returns a cursor object using the ``Transaction.connection``.
+
 .. method:: Transaction.start(database_name, user[, readonly[, context[, close[, autocommit]]]])
 
     Start a new transaction and return a `context manager`_.
 
 .. method:: Transaction.stop()
 
-    Stop a started transaction. This method should not be called directly as it
-    will be by the context manager when exiting the `with` statement.
+    Stop a started transaction and pop it from the stack of transactions.
+
+    This method should not be called directly as it will be by the context
+    manager when exiting the `with` statement.
 
 .. method:: Transaction.set_context(context, \**kwargs)
 
@@ -63,15 +71,28 @@ database transaction.
     `set_context` will put the previous user id in the context to simulate the
     record rules. The user will be restored when exiting the `with` statement.
 
-.. method:: Transaction.set_cursor(cursor)
+.. method:: Transaction.set_current_transaction(transaction)
+
+    Add a specific ``transaction`` on the top of the transaction stack. A
+    transaction is commited or rollbacked only when its last reference is
+    popped from the stack.
+
+.. method:: Transaction.new_transaction([autocommit[, readonly]])
+
+    Create a new transaction with the same database, user and context as the
+    original transaction and adds it to the stack of transactions.
 
-    Modify the cursor of the transaction and return a `context manager`_. The
-    previous cursor will be restored when exiting the `with` statement.
+.. method:: Transaction.join(datamanager)
 
-.. method:: Transaction.new_cursor([autocommit[, readonly]])
+    Register in the transaction a data manager conforming to the `Two-Phase
+    Commit protocol`_. More information on how to implement such data manager
+    is available at the `Zope documentation`_.
 
-    Change the cursor of the transaction with a new one on the same database
-    and return a `context manager`_. The previous cursor will be restored when
-    exiting the `with` statement and the new one will be closed.
+    This method returns the registered datamanager. It could be a different yet
+    equivalent (in term of python equality) datamanager than the one passed to the
+    method.
 
 .. _`context manager`: http://docs.python.org/reference/datamodel.html#context-managers
+.. _`PEP-0249`: https://www.python.org/dev/peps/pep-0249/
+.. _`Two-Phase Commit protocol`: https://en.wikipedia.org/wiki/Two-phase_commit_protocol
+.. _`Zope documentation`: http://zodb.readthedocs.org/en/latest/transactions.html#the-two-phase-commit-protocol-in-practice
diff --git a/doc/topics/access_rights.rst b/doc/topics/access_rights.rst
index 5f625e0..0e69bba 100644
--- a/doc/topics/access_rights.rst
+++ b/doc/topics/access_rights.rst
@@ -26,10 +26,19 @@ Same as for model access but applied on the field. It uses records of
 Button
 ======
 
-For each button of a model the records of 'ir.model.button` define the list of
+For each button of a model the records of `ir.model.button` define the list of
 groups that are allowed to call it.
 
 Record Rule
 ===========
 
-.. TODO
+They are defined by records of `ir.rule.group` which contains a list of
+`ir.rule` domain to which the rule applies. The group are selected by groups or
+users. The access is granted for a record:
+
+    - if the user is in at least one group that has the permission activated,
+
+    - or if the user is in no group by there is a default group with the
+      permission,
+
+    - or if there is a global group with the permission.
diff --git a/doc/topics/actions.rst b/doc/topics/actions.rst
index 015a5f1..da68525 100644
--- a/doc/topics/actions.rst
+++ b/doc/topics/actions.rst
@@ -22,12 +22,10 @@ Keyword
 
 Keywords define where to display the action in the client.
 
-There are six places:
+There are five places:
 
     * Open tree (`tree_open`)
 
-    * Action tree (`tree_action`)
-
     * Print form (`form_print`)
 
     * Action form (`form_action`)
diff --git a/doc/topics/configuration.rst b/doc/topics/configuration.rst
index 4d31d6c..f02029f 100644
--- a/doc/topics/configuration.rst
+++ b/doc/topics/configuration.rst
@@ -29,51 +29,31 @@ possible values.
 Some modules could request the usage of other sections for which the guideline
 asks them to be named like their module.
 
-jsonrpc
--------
+web
+---
 
-Defines the behavior of the JSON-RPC_ network interface.
+Defines the behavior of the web interface.
 
 listen
 ~~~~~~
 
-Defines a comma separated list of couples of host (or IP address) and port
-number separated by a colon to listen on.
+Defines the couple of host (or IP address) and port number separated by a colon
+to listen on.
 
 Default `localhost:8000`
 
 hostname
 ~~~~~~~~
 
-Defines the hostname for this network interface.
+Defines the hostname.
 
-data
+root
 ~~~~
 
-Defines the root path to retrieve data for `GET` requests.
+Defines the root path served by `GET` requests.
 
 Default: `/var/www/localhost/tryton`
 
-xmlrpc
-------
-
-Defines the behavior of the XML-RPC_ network interface.
-
-listen
-~~~~~~
-
-Same as for `jsonrpc` except it has no default value.
-
-webdav
-------
-
-Define the behavior of the WebDAV_ network interface.
-
-listen
-~~~~~~
-
-Same as for `jsonrpc` except it has no default value.
-
 database
 --------
 
@@ -250,7 +230,6 @@ Default: `pipe,name=trytond;urp;StarOffice.ComponentContext`
 
 .. _JSON-RPC: http://en.wikipedia.org/wiki/JSON-RPC
 .. _XML-RPC: http://en.wikipedia.org/wiki/XML-RPC
-.. _WebDAV: http://en.wikipedia.org/wiki/WebDAV
 .. _RFC-3986: http://tools.ietf.org/html/rfc3986
 .. _SMTP-URL: http://tools.ietf.org/html/draft-earhart-url-smtp-00
 .. _SSL: http://en.wikipedia.org/wiki/Secure_Sockets_Layer
diff --git a/doc/topics/domain.rst b/doc/topics/domain.rst
index 616d1fd..fdc1597 100644
--- a/doc/topics/domain.rst
+++ b/doc/topics/domain.rst
@@ -227,4 +227,30 @@ pattern, unless otherwise noted::
     Is a parent child comparison operator. It is the negation of the
     `child_of`_ operator.
 
+``parent_of``
+-------------
+
+    Is a parent child comparison operator. It is the same as `child_of`_
+    operator but if ``<field name>`` is a parent of ``<operand>``.
+
+``not parent_of``
+-----------------
+
+    Is a parent child comparison operator. it is the negation of this
+    `parent_of`_ operator.
+
+``where``
+---------
+
+    Is a :class:`trytond.model.fields.One2Many` /
+    :class:`trytond.model.fields.Many2Many` domain operator. It returns true
+    for every row of the target model that match the domain specified as
+    ``<operand>``.
+
+``not where``
+-------------
 
+    Is a :class:`trytond.model.fields.One2Many` /
+    :class:`trytond.model.fields.Many2Many` domain operator. It returns true
+    for every row of the target model that does not match the domain specified
+    as ``<operand>``.
diff --git a/doc/topics/index.rst b/doc/topics/index.rst
index c19ba8a..6560776 100644
--- a/doc/topics/index.rst
+++ b/doc/topics/index.rst
@@ -13,6 +13,7 @@ Introduction to all the key parts of trytond:
     configuration
     setup_database
     logs
+    start_server
     models/index
     models/fields_default_value
     models/fields_on_change
diff --git a/doc/topics/install.rst b/doc/topics/install.rst
index 889e360..4a08e98 100644
--- a/doc/topics/install.rst
+++ b/doc/topics/install.rst
@@ -8,17 +8,18 @@ Prerequisites
 =============
 
     * Python 2.7 or later (http://www.python.org/)
+    * Werkzeug (http://werkzeug.pocoo.org/)
+    * wrapt (https://github.com/GrahamDumpleton/wrapt)
     * lxml 2.0 or later (http://lxml.de/)
     * relatorio 0.2.0 or later (http://code.google.com/p/python-relatorio/)
     * Genshi (http://genshi.edgewall.org/)
     * python-dateutil (http://labix.org/python-dateutil)
     * polib (https://bitbucket.org/izi/polib/wiki/Home)
-    * python-sql 0.2 or later (http://code.google.com/p/python-sql/)
-    * Optional: psycopg 2 or later (http://www.initd.org/)
+    * python-sql 0.4 or later (http://code.google.com/p/python-sql/)
+    * Optional: psycopg 2.5.0 or later (http://www.initd.org/)
     * Optional: psycopg2cffi 2.5.0 or later
       (http://github.com/chtd/psycopg2cffi)
     * Optional: MySQL-python (http://sourceforge.net/projects/mysql-python/)
-    * Optional: pywebdav 0.9.8 or later (http://code.google.com/p/pywebdav/)
     * Optional: pydot (http://code.google.com/p/pydot/)
     * Optional: unoconv http://dag.wieers.com/home-made/unoconv/)
     * Optional: sphinx (http://sphinx.pocoo.org/)
diff --git a/doc/topics/modules/index.rst b/doc/topics/modules/index.rst
index f1694ed..21d0638 100644
--- a/doc/topics/modules/index.rst
+++ b/doc/topics/modules/index.rst
@@ -6,7 +6,7 @@ Modules
 
 The modules of Tryton extend the functionality of the platform. The server
 comes by default with only a basic functionality included in these modules:
-``ir``, ``res``, ``webdav``.
+``ir``, ``res``.
 
 Module Structure
 ================
diff --git a/doc/topics/setup_database.rst b/doc/topics/setup_database.rst
index fe5ed91..977602d 100644
--- a/doc/topics/setup_database.rst
+++ b/doc/topics/setup_database.rst
@@ -20,7 +20,7 @@ Initialize a database
 
 A database can be initialized using this command line::
 
-    trytond -c <config file> -d <database name> --all
+    trytond-admin -c <config file> -d <database name> --all
 
-At the end of the process, `trytond` will ask to set the password for the
+At the end of the process, `trytond-admin` will ask to set the password for the
 `admin` user.
diff --git a/doc/topics/start_server.rst b/doc/topics/start_server.rst
new file mode 100644
index 0000000..71853ba
--- /dev/null
+++ b/doc/topics/start_server.rst
@@ -0,0 +1,41 @@
+.. _topics-start-server:
+
+=======================
+How to start the server
+=======================
+
+Web service
+===========
+
+You can start the default web server bundled in Tryton with this command line::
+
+    trytond -c <config file>
+
+The server will wait for client connections on the interface defined in the
+`web` section of the :ref:`configuration <topics-configuration>`.
+
+WSGI server
+-----------
+
+If you prefer to run Tryton inside your own WSGI server instead of the simple
+server of Werkzeug, you can use the application `trytond.application.app` and
+set the environment variable `TRYTOND_CONFIG` to point to the
+:ref:`configuration <topics-configuration>`.
+
+.. warning:: You must manage to serve the static files from the web root.
+
+Cron service
+============
+
+If you want to run some scheduled actions, you must also run the cron server
+with this command line::
+
+    trytond-cron -c <config file> -d <database>
+
+The server will wake up every minutes and preform the scheduled actions defined
+in the `database`.
+
+Services options
+================
+
+You will find more options for those services by using `--help` arguments.
diff --git a/doc/topics/views/index.rst b/doc/topics/views/index.rst
index eda830c..2d8e0f1 100644
--- a/doc/topics/views/index.rst
+++ b/doc/topics/views/index.rst
@@ -37,6 +37,10 @@ There is three types of views:
 
     * Graph
 
+    * Board
+
+    * Calendar
+
 Form view
 =========
 
@@ -55,7 +59,7 @@ Elements of the view are put on the screen following the rules:
 
     * Elements take one or more columns when they are put in the table. If
       there are not enough free columns on the current row, the elements are put
-      at the begining of the next row.
+      at the beginning of the next row.
 
 
 XML description
@@ -267,8 +271,8 @@ image
 
 Display an image.
 
-    * ``name``: the name of the image. It must be the name with the extension
-      of an image from ``tryton/share/pixmaps/``.
+    * ``name``: the name of the image. It must be the name of a record of
+      `ir.ui.icon`.
 
     * ``yexpand``: see in common-attributes-yexpand_.
 
diff --git a/setup.py b/setup.py
index 657be71..c512efd 100644
--- a/setup.py
+++ b/setup.py
@@ -5,11 +5,14 @@
 from setuptools import setup, find_packages
 import os
 import re
+import io
 import platform
 
 
 def read(fname):
-    return open(os.path.join(os.path.dirname(__file__), fname)).read()
+    return io.open(
+        os.path.join(os.path.dirname(__file__), fname),
+        'r', encoding='utf-8').read()
 
 
 def get_version():
@@ -32,7 +35,7 @@ if minor_version % 2:
 if platform.python_implementation() == 'PyPy':
     pg_require = ['psycopg2cffi >= 2.5']
 else:
-    pg_require = ['psycopg2 >= 2.0']
+    pg_require = ['psycopg2 >= 2.5']
 
 setup(name=name,
     version=version,
@@ -54,10 +57,9 @@ setup(name=name,
         'trytond.ir.module': ['*.xml'],
         'trytond.ir.ui': ['*.xml', '*.rng', '*.rnc'],
         'trytond.res': ['tryton.cfg', '*.xml', 'view/*.xml', 'locale/*.po'],
-        'trytond.webdav': ['tryton.cfg', '*.xml', 'view/*.xml', 'locale/*.po'],
         'trytond.tests': ['tryton.cfg', '*.xml'],
         },
-    scripts=['bin/trytond'],
+    scripts=['bin/trytond', 'bin/trytond-admin', 'bin/trytond-cron'],
     classifiers=[
         'Development Status :: 5 - Production/Stable',
         'Environment :: No Input/Output (Daemon)',
@@ -66,6 +68,7 @@ setup(name=name,
         'License :: OSI Approved :: GNU General Public License (GPL)',
         'Natural Language :: Bulgarian',
         'Natural Language :: Catalan',
+        'Natural Language :: Chinese (Simplified)',
         'Natural Language :: Czech',
         'Natural Language :: Dutch',
         'Natural Language :: English',
@@ -79,6 +82,9 @@ setup(name=name,
         'Natural Language :: Spanish',
         'Operating System :: OS Independent',
         'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
         'Topic :: Software Development :: Libraries :: Application Frameworks',
@@ -92,11 +98,12 @@ setup(name=name,
         'python-dateutil',
         'polib',
         'python-sql >= 0.4',
+        'werkzeug',
+        'wrapt',
         ],
     extras_require={
         'PostgreSQL': pg_require,
         'MySQL': ['MySQL-python'],
-        'WebDAV': ['PyWebDAV >= 0.9.8'],
         'unoconv': ['unoconv'],
         'graphviz': ['pydot'],
         'simplejson': ['simplejson'],
@@ -108,4 +115,5 @@ setup(name=name,
     test_suite='trytond.tests',
     test_loader='trytond.test_loader:Loader',
     tests_require=['mock'],
+    use_2to3=True,
     )
diff --git a/trytond.egg-info/PKG-INFO b/trytond.egg-info/PKG-INFO
index eaae680..ec59371 100644
--- a/trytond.egg-info/PKG-INFO
+++ b/trytond.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 3.8.5
+Version: 4.0.0
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
 Author-email: issue_tracker at tryton.org
 License: GPL-3
-Download-URL: http://downloads.tryton.org/3.8/
+Download-URL: http://downloads.tryton.org/4.0/
 Description: trytond
         =======
         
@@ -106,6 +106,7 @@ Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU General Public License (GPL)
 Classifier: Natural Language :: Bulgarian
 Classifier: Natural Language :: Catalan
+Classifier: Natural Language :: Chinese (Simplified)
 Classifier: Natural Language :: Czech
 Classifier: Natural Language :: Dutch
 Classifier: Natural Language :: English
@@ -119,6 +120,9 @@ Classifier: Natural Language :: Slovenian
 Classifier: Natural Language :: Spanish
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
diff --git a/trytond.egg-info/SOURCES.txt b/trytond.egg-info/SOURCES.txt
index 7df8bed..cfa8af9 100644
--- a/trytond.egg-info/SOURCES.txt
+++ b/trytond.egg-info/SOURCES.txt
@@ -6,6 +6,8 @@ MANIFEST.in
 README
 setup.py
 bin/trytond
+bin/trytond-admin
+bin/trytond-cron
 doc/Makefile
 doc/conf.py
 doc/index.rst
@@ -14,6 +16,7 @@ doc/ref/index.rst
 doc/ref/pool.rst
 doc/ref/pyson.rst
 doc/ref/rpc.rst
+doc/ref/sendmail.rst
 doc/ref/transaction.rst
 doc/ref/wizard.rst
 doc/ref/models/fields.rst
@@ -29,6 +32,7 @@ doc/topics/install.rst
 doc/topics/logs.rst
 doc/topics/pyson.rst
 doc/topics/setup_database.rst
+doc/topics/start_server.rst
 doc/topics/translation.rst
 doc/topics/wizard.rst
 doc/topics/models/fields_default_value.rst
@@ -39,21 +43,25 @@ doc/topics/reports/index.rst
 doc/topics/views/extension.rst
 doc/topics/views/index.rst
 trytond/__init__.py
+trytond/admin.py
+trytond/application.py
 trytond/cache.py
+trytond/commandline.py
 trytond/config.py
 trytond/const.py
 trytond/convert.py
+trytond/cron.py
 trytond/error.py
 trytond/exceptions.py
-trytond/monitor.py
 trytond/pool.py
 trytond/pyson.py
 trytond/rpc.py
 trytond/security.py
-trytond/server.py
+trytond/sendmail.py
 trytond/test_loader.py
 trytond/transaction.py
 trytond/url.py
+trytond/wsgi.py
 trytond.egg-info/PKG-INFO
 trytond.egg-info/SOURCES.txt
 trytond.egg-info/dependency_links.txt
@@ -95,8 +103,11 @@ trytond/ir/model.py
 trytond/ir/model.xml
 trytond/ir/module.py
 trytond/ir/module.xml
+trytond/ir/note.py
+trytond/ir/note.xml
 trytond/ir/property.py
 trytond/ir/property.xml
+trytond/ir/resource.py
 trytond/ir/rule.py
 trytond/ir/rule.xml
 trytond/ir/sequence.py
@@ -121,11 +132,13 @@ trytond/ir/locale/fr_FR.po
 trytond/ir/locale/hu_HU.po
 trytond/ir/locale/it_IT.po
 trytond/ir/locale/ja_JP.po
+trytond/ir/locale/lo_LA.po
 trytond/ir/locale/lt_LT.po
 trytond/ir/locale/nl_NL.po
 trytond/ir/locale/pt_BR.po
 trytond/ir/locale/ru_RU.po
 trytond/ir/locale/sl_SI.po
+trytond/ir/locale/zh_CN.po
 trytond/ir/ui/__init__.py
 trytond/ir/ui/board.rnc
 trytond/ir/ui/board.rng
@@ -204,6 +217,8 @@ trytond/ir/view/module_form.xml
 trytond/ir/view/module_install_upgrade_done_form.xml
 trytond/ir/view/module_install_upgrade_start_form.xml
 trytond/ir/view/module_list.xml
+trytond/ir/view/note_form.xml
+trytond/ir/view/note_list.xml
 trytond/ir/view/property_form.xml
 trytond/ir/view/property_list.xml
 trytond/ir/view/rule_form.xml
@@ -271,11 +286,9 @@ trytond/model/fields/sha.py
 trytond/model/fields/text.py
 trytond/modules/__init__.py
 trytond/protocols/__init__.py
-trytond/protocols/common.py
 trytond/protocols/dispatcher.py
 trytond/protocols/jsonrpc.py
-trytond/protocols/sslsocket.py
-trytond/protocols/webdav.py
+trytond/protocols/wrappers.py
 trytond/protocols/xmlrpc.py
 trytond/report/__init__.py
 trytond/report/report.py
@@ -301,11 +314,13 @@ trytond/res/locale/fr_FR.po
 trytond/res/locale/hu_HU.po
 trytond/res/locale/it_IT.po
 trytond/res/locale/ja_JP.po
+trytond/res/locale/lo_LA.po
 trytond/res/locale/lt_LT.po
 trytond/res/locale/nl_NL.po
 trytond/res/locale/pt_BR.po
 trytond/res/locale/ru_RU.po
 trytond/res/locale/sl_SI.po
+trytond/res/locale/zh_CN.po
 trytond/res/view/group_form.xml
 trytond/res/view/group_list.xml
 trytond/res/view/sequence_type_form.xml
@@ -348,6 +363,7 @@ trytond/tests/test_mptt.py
 trytond/tests/test_protocols.py
 trytond/tests/test_pyson.py
 trytond/tests/test_res.py
+trytond/tests/test_sendmail.py
 trytond/tests/test_sequence.py
 trytond/tests/test_tools.py
 trytond/tests/test_transaction.py
@@ -355,7 +371,6 @@ trytond/tests/test_trigger.py
 trytond/tests/test_tryton.py
 trytond/tests/test_union.py
 trytond/tests/test_user.py
-trytond/tests/test_webdav.py
 trytond/tests/test_wizard.py
 trytond/tests/test_workflow.py
 trytond/tests/trigger.py
@@ -370,33 +385,5 @@ trytond/tools/datetime_strftime.py
 trytond/tools/decimal_.py
 trytond/tools/misc.py
 trytond/tools/singleton.py
-trytond/webdav/__init__.py
-trytond/webdav/tryton.cfg
-trytond/webdav/webdav.py
-trytond/webdav/webdav.xml
-trytond/webdav/locale/bg_BG.po
-trytond/webdav/locale/ca_ES.po
-trytond/webdav/locale/cs_CZ.po
-trytond/webdav/locale/de_DE.po
-trytond/webdav/locale/es_AR.po
-trytond/webdav/locale/es_CO.po
-trytond/webdav/locale/es_EC.po
-trytond/webdav/locale/es_ES.po
-trytond/webdav/locale/es_MX.po
-trytond/webdav/locale/fr_FR.po
-trytond/webdav/locale/hu_HU.po
-trytond/webdav/locale/it_IT.po
-trytond/webdav/locale/ja_JP.po
-trytond/webdav/locale/lt_LT.po
-trytond/webdav/locale/nl_NL.po
-trytond/webdav/locale/pt_BR.po
-trytond/webdav/locale/ru_RU.po
-trytond/webdav/locale/sl_SI.po
-trytond/webdav/view/attachment_form.xml
-trytond/webdav/view/collection_form.xml
-trytond/webdav/view/collection_list.xml
-trytond/webdav/view/collection_tree.xml
-trytond/webdav/view/share_form.xml
-trytond/webdav/view/share_list.xml
 trytond/wizard/__init__.py
 trytond/wizard/wizard.py
\ No newline at end of file
diff --git a/trytond.egg-info/requires.txt b/trytond.egg-info/requires.txt
index 12c57b9..421dcfa 100644
--- a/trytond.egg-info/requires.txt
+++ b/trytond.egg-info/requires.txt
@@ -4,6 +4,8 @@ Genshi
 python-dateutil
 polib
 python-sql >= 0.4
+werkzeug
+wrapt
 
 [BCrypt]
 bcrypt
@@ -15,10 +17,7 @@ python-Levenshtein
 MySQL-python
 
 [PostgreSQL]
-psycopg2 >= 2.0
-
-[WebDAV]
-PyWebDAV >= 0.9.8
+psycopg2 >= 2.5
 
 [cdecimal]
 cdecimal
diff --git a/trytond/__init__.py b/trytond/__init__.py
index 43b3472..44be727 100644
--- a/trytond/__init__.py
+++ b/trytond/__init__.py
@@ -2,13 +2,18 @@
 # this repository contains the full copyright notices and license terms.
 import os
 import time
+import logging
 from email import charset
 
-__version__ = "3.8.5"
+__version__ = "4.0.0"
+logger = logging.getLogger(__name__)
 
 os.environ['TZ'] = 'UTC'
 if hasattr(time, 'tzset'):
     time.tzset()
 
+if time.tzname[0] != 'UTC':
+    logger.error('Timezone must be set to UTC instead of %s', time.tzname[0])
+
 # set email encoding for utf-8 to 'quoted-printable'
 charset.add_charset('utf-8', charset.QP, charset.QP)
diff --git a/trytond/admin.py b/trytond/admin.py
new file mode 100644
index 0000000..aa5374f
--- /dev/null
+++ b/trytond/admin.py
@@ -0,0 +1,83 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import sys
+import os
+import logging
+from getpass import getpass
+
+from sql import Table
+
+from trytond.transaction import Transaction
+from trytond import backend
+from trytond.pool import Pool
+
+__all__ = ['run']
+logger = logging.getLogger(__name__)
+
+
+def run(options):
+    Database = backend.get('Database')
+    init = {}
+    for db_name in options.database_names:
+        init[db_name] = False
+        with Transaction().start(db_name, 0):
+            database = Database(db_name)
+            database.connect()
+            if options.update:
+                if not database.test():
+                    logger.info("init db")
+                    database.init()
+                    init[db_name] = True
+            elif not database.test():
+                raise Exception("'%s' is not a Tryton database!" % db_name)
+
+    for db_name in options.database_names:
+        if options.update:
+            with Transaction().start(db_name, 0) as transaction,\
+                    transaction.connection.cursor() as cursor:
+                database = Database(db_name)
+                database.connect()
+                if not database.test():
+                    raise Exception("'%s' is not a Tryton database!" % db_name)
+                lang = Table('ir_lang')
+                cursor.execute(*lang.select(lang.code,
+                        where=lang.translatable == True))
+                lang = [x[0] for x in cursor.fetchall()]
+        else:
+            lang = None
+        Pool(db_name).init(update=options.update, lang=lang)
+
+    for db_name in options.database_names:
+        if init[db_name]:
+            # try to read password from environment variable
+            # TRYTONPASSFILE, empty TRYTONPASSFILE ignored
+            passpath = os.getenv('TRYTONPASSFILE')
+            password = ''
+            if passpath:
+                try:
+                    with open(passpath) as passfile:
+                        password = passfile.readline()[:-1]
+                except Exception, err:
+                    sys.stderr.write('Can not read password '
+                        'from "%s": "%s"\n' % (passpath, err))
+
+            if not password:
+                while True:
+                    password = getpass('Admin Password for %s: ' % db_name)
+                    password2 = getpass('Admin Password Confirmation: ')
+                    if password != password2:
+                        sys.stderr.write('Admin Password Confirmation '
+                            'doesn\'t match Admin Password!\n')
+                        continue
+                    if not password:
+                        sys.stderr.write('Admin Password is required!\n')
+                        continue
+                    break
+
+            with Transaction().start(db_name, 0) as transaction:
+                pool = Pool()
+                User = pool.get('res.user')
+                admin, = User.search([('login', '=', 'admin')])
+                User.write([admin], {
+                        'password': password,
+                        })
diff --git a/trytond/application.py b/trytond/application.py
new file mode 100644
index 0000000..ef3b73b
--- /dev/null
+++ b/trytond/application.py
@@ -0,0 +1,9 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.pool import Pool
+from trytond.wsgi import app
+
+__all__ = ['app']
+
+Pool.start()
+import trytond.protocols.dispatcher
diff --git a/trytond/backend/__init__.py b/trytond/backend/__init__.py
index 31f1bf1..b82e8bb 100644
--- a/trytond/backend/__init__.py
+++ b/trytond/backend/__init__.py
@@ -24,10 +24,14 @@ def get(prop):
     if modname not in sys.modules:
         try:
             __import__(modname)
-        except ImportError:
+        except ImportError, exception:
             if not pkg_resources:
-                raise
-            ep, = pkg_resources.iter_entry_points('trytond.backend', db_type)
+                raise exception
+            try:
+                ep, = pkg_resources.iter_entry_points(
+                    'trytond.backend', db_type)
+            except ValueError:
+                raise exception
             mod_path = os.path.join(ep.dist.location,
                 *ep.module_name.split('.')[:-1])
             fp, pathname, description = imp.find_module(db_type, [mod_path])
diff --git a/trytond/backend/database.py b/trytond/backend/database.py
index 06f618f..22567cd 100644
--- a/trytond/backend/database.py
+++ b/trytond/backend/database.py
@@ -1,7 +1,5 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.config import config
-
 DatabaseIntegrityError = None
 DatabaseOperationalError = None
 
@@ -11,12 +9,13 @@ class DatabaseInterface(object):
     Define generic interface for database connection
     '''
     flavor = None
+    IN_MAX = 1000
 
-    def __new__(cls, database_name=''):
+    def __new__(cls, name=''):
         return object.__new__(cls)
 
-    def __init__(self, database_name=''):
-        self.database_name = database_name
+    def __init__(self, name=''):
+        self.name = name
 
     def connect(self):
         '''
@@ -26,12 +25,18 @@ class DatabaseInterface(object):
         '''
         raise NotImplementedError
 
-    def cursor(self, autocommit=False, readonly=False):
+    def get_connection(self, autocommit, readonly=False):
+        '''Retrieve a connection on the database
+
+        :param autocommit: a boolean to activate autocommit
+        :param readonly: a boolean to specify if the transaction is readonly
         '''
-        Retreive a cursor on the database
+        raise NotImplementedError
 
-        :param autocommit: a boolean to active autocommit
-        :return: a Cursor
+    def put_connection(self, connection, close=False):
+        '''Release the connection
+
+        :param close: if close is True the connection is discarded
         '''
         raise NotImplementedError
 
@@ -41,21 +46,21 @@ class DatabaseInterface(object):
         '''
         raise NotImplementedError
 
-    @staticmethod
-    def create(cursor, database_name):
+    @classmethod
+    def create(cls, connection, database_name):
         '''
         Create a database
 
-        :param database_name: the database name
+        :param connection: the connection to the database
+        :param database_name: the new database name
         '''
         raise NotImplementedError
 
-    @staticmethod
-    def drop(cursor, database_name):
+    def drop(self, connection, database_name):
         '''
         Drop a database
 
-        :param cursor: a cursor on an other database
+        :param connection: the connection to the database
         :param database_name: the database name
         '''
         raise NotImplementedError
@@ -81,8 +86,7 @@ class DatabaseInterface(object):
         '''
         raise NotImplementedError
 
-    @staticmethod
-    def list(cursor):
+    def list(self):
         '''
         Get the list of database
 
@@ -90,107 +94,60 @@ class DatabaseInterface(object):
         '''
         raise NotImplementedError
 
-    @staticmethod
-    def init(cursor):
+    def init(self):
         '''
         Initialize a database
-
-        :param cursor: a cursor on the database
-        '''
-        raise NotImplementedError
-
-
-class CursorInterface(object):
-    '''
-    Define generic interface for database cursor
-    '''
-    IN_MAX = 1000
-    cache_keys = {'language', 'fuzzy_translation', '_datetime'}
-
-    def __init__(self):
-        self.cache = {}
-
-    def get_cache(self):
-        from trytond.cache import LRUDict
-        from trytond.transaction import Transaction
-        user = Transaction().user
-        context = Transaction().context
-        keys = tuple(((key, context[key]) for key in sorted(self.cache_keys)
-                if key in context))
-        return self.cache.setdefault((user, keys),
-            LRUDict(config.getint('cache', 'model')))
-
-    def execute(self, sql, params=None):
-        '''
-        Execute a query
-
-        :param sql: a sql query string
-        :param params: a tuple or list of parameters
-        '''
-        raise NotImplementedError
-
-    def close(self, close=False):
-        '''
-        Close the cursor
-
-        :param close: boolean to not release cursor in pool
         '''
         raise NotImplementedError
 
-    def commit(self):
-        '''
-        Commit the cursor
-        '''
-        for cache in self.cache.itervalues():
-            cache.clear()
-
-    def rollback(self):
-        '''
-        Rollback the cursor
-        '''
-        for cache in self.cache.itervalues():
-            cache.clear()
-
     def test(self):
         '''
         Test if it is a Tryton database.
         '''
         raise NotImplementedError
 
-    def nextid(self, table):
+    def nextid(self, connection, table):
         '''
         Return the next sequenced id for a table.
 
+        :param connection: a connection on the database
         :param table: the table name
         :return: an integer
         '''
 
-    def setnextid(self, table, value):
+    def setnextid(self, connection, table, value):
         '''
         Set the current sequenced id for a table.
 
+        :param connection: a connection on the database
         :param table: the table name
         '''
 
-    def currid(self, table):
+    def currid(self, connection, table):
         '''
         Return the current sequenced id for a table.
 
+        :param connection: a connection on the database
         :param table: the table name
         :return: an integer
         '''
 
-    def lastid(self):
+    def update_auto_increment(self, connection, table, value):
         '''
-        Return the last id inserted.
+        Update auto_increment value of table
 
-        :return: an integer
+        :param connection: a connection on the database
+        :param table: the table name
+        :param value: the auto_increment value
         '''
+        pass
 
-    def lock(self, table):
+    @classmethod
+    def lock(cls, connection, table):
         '''
         Lock the table
 
+        :param connection: a connection on the database
         :param table: the table name
         '''
         raise NotImplementedError
@@ -203,15 +160,6 @@ class CursorInterface(object):
         '''
         raise NotImplementedError
 
-    def update_auto_increment(self, table, value):
-        '''
-        Update auto_increment value of table
-
-        :param table: the table name
-        :param value: the auto_increment value
-        '''
-        pass
-
     def has_returning(self):
         '''
         Return True if database implements RETURNING clause in INSERT or UPDATE
@@ -219,26 +167,8 @@ class CursorInterface(object):
 
         :return: a boolean
         '''
+        return False
 
     def has_multirow_insert(self):
         'Return True if database supports multirow insert'
         return False
-
-    def __build_dict(self, row):
-        return dict((desc[0], row[i])
-                for i, desc in enumerate(self.description))
-
-    def dictfetchone(self):
-        row = self.fetchone()
-        if row:
-            return self.__build_dict(row)
-        else:
-            return row
-
-    def dictfetchmany(self, size):
-        rows = self.fetchmany(size)
-        return [self.__build_dict(row) for row in rows]
-
-    def dictfetchall(self):
-        rows = self.fetchall()
-        return [self.__build_dict(row) for row in rows]
diff --git a/trytond/backend/mysql/database.py b/trytond/backend/mysql/database.py
index 0c6d349..0c091f6 100644
--- a/trytond/backend/mysql/database.py
+++ b/trytond/backend/mysql/database.py
@@ -1,6 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.backend.database import DatabaseInterface, CursorInterface
+from trytond.backend.database import DatabaseInterface
 from trytond.config import config, parse_uri
 import MySQLdb
 import MySQLdb.cursors
@@ -15,8 +15,7 @@ import urllib
 from sql import Flavor, Expression
 from sql.functions import Extract, Overlay, CharLength
 
-__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError',
-    'Cursor']
+__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
 
 
 class MySQLExtract(Extract):
@@ -82,12 +81,12 @@ class Database(DatabaseInterface):
     def connect(self):
         return self
 
-    def cursor(self, autocommit=False, readonly=False):
+    def get_connection(self, autocommit=False, readonly=False):
         conv = MySQLdb.converters.conversions.copy()
         conv[float] = lambda value, _: repr(value)
         conv[MySQLdb.constants.FIELD_TYPE.TIME] = MySQLdb.times.Time_or_None
         args = {
-            'db': self.database_name,
+            'db': self.name,
             'sql_mode': 'traditional,postgresql',
             'use_unicode': True,
             'charset': 'utf8',
@@ -104,21 +103,26 @@ class Database(DatabaseInterface):
         if uri.password:
             args['passwd'] = urllib.unquote_plus(uri.password)
         conn = MySQLdb.connect(**args)
-        cursor = Cursor(conn, self.database_name)
+        cursor = conn.cursor()
         cursor.execute('SET time_zone = `UTC`')
-        return cursor
+        return conn
+
+    def put_connection(self, connection, close=False):
+        connection.close()
 
     def close(self):
         return
 
     @classmethod
-    def create(cls, cursor, database_name):
+    def create(cls, connection, database_name):
+        cursor = connection.cursor()
         cursor.execute('CREATE DATABASE `' + database_name + '` '
             'DEFAULT CHARACTER SET = \'utf8\'')
         cls._list_cache = None
 
     @classmethod
-    def drop(cls, cursor, database_name):
+    def drop(cls, connection, database_name):
+        cursor = connection.cursor()
         cursor.execute('DROP DATABASE `' + database_name + '`')
         cls._list_cache = None
 
@@ -195,13 +199,14 @@ class Database(DatabaseInterface):
         Database._list_cache = None
         return True
 
-    @staticmethod
-    def list(cursor):
+    def list(self):
         now = time.time()
         timeout = config.getint('session', 'timeout')
         res = Database._list_cache
         if res and abs(Database._list_cache_timestamp - now) < timeout:
             return res
+        conn = self.get_connection()
+        cursor = conn.cursor()
         cursor.execute('SHOW DATABASES')
         res = []
         for db_name, in cursor.fetchall():
@@ -209,27 +214,26 @@ class Database(DatabaseInterface):
                 database = Database(db_name).connect()
             except Exception:
                 continue
-            cursor2 = database.cursor()
-            if cursor2.test():
+            if database.test():
                 res.append(db_name)
-                cursor2.close(close=True)
-            else:
-                cursor2.close()
-                database.close()
+            database.close()
+        self.put_connection(conn)
         Database._list_cache = res
         Database._list_cache_timestamp = now
         return res
 
-    @staticmethod
-    def init(cursor):
+    def init(self):
         from trytond.modules import get_module_info
+
+        connection = self.get_connection()
+        cursor = connection.cursor()
         sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
         with open(sql_file) as fp:
             for line in fp.read().split(';'):
                 if (len(line) > 0) and (not line.isspace()):
                     cursor.execute(line)
 
-        for module in ('ir', 'res', 'webdav'):
+        for module in ('ir', 'res'):
             state = 'uninstalled'
             if module in ('ir', 'res'):
                 state = 'to install'
@@ -246,40 +250,15 @@ class Database(DatabaseInterface):
                     'VALUES (%s, now(), %s, %s)',
                     (0, module_id, dependency))
 
-
-class Cursor(CursorInterface):
-
-    def __init__(self, conn, database_name):
-        super(Cursor, self).__init__()
-        self._conn = conn
-        self.database_name = database_name
-        self.dbname = self.database_name  # XXX to remove
-        self.cursor = conn.cursor()
-
-    def __getattr__(self, name):
-        return getattr(self.cursor, name)
-
-    def execute(self, sql, params=None):
-        if params:
-            return self.cursor.execute(sql, params)
-        else:
-            return self.cursor.execute(sql)
-
-    def close(self, close=False):
-        self.cursor.close()
-        self.rollback()
-
-    def commit(self):
-        super(Cursor, self).commit()
-        self._conn.commit()
-
-    def rollback(self):
-        super(Cursor, self).rollback()
-        self._conn.rollback()
+        connection.commit()
+        self.put_connection(connection)
 
     def test(self):
-        self.cursor.execute("SHOW TABLES")
-        for table, in self.cursor.fetchall():
+        is_tryton_database = False
+        connection = self.get_connection()
+        cursor = connection.cursor()
+        cursor.execute("SHOW TABLES")
+        for table, in cursor.fetchall():
             if table in (
                     'ir_model',
                     'ir_model_field',
@@ -292,14 +271,17 @@ class Cursor(CursorInterface):
                     'ir_translation',
                     'ir_lang',
                     ):
-                return True
-        return False
+                is_tryton_database = True
+                break
+        self.put_connection(connection)
+        return is_tryton_database
 
-    def lastid(self):
-        self.cursor.execute('SELECT LAST_INSERT_ID()')
-        return self.cursor.fetchone()[0]
+    def lastid(self, cursor):
+        # This call is not thread safe
+        cursor.execute('SELECT LAST_INSERT_ID()')
+        return cursor.fetchone()[0]
 
-    def lock(self, table):
+    def lock(self, connection, table):
         # Lock of table doesn't work because MySQL require
         # that the session locks all tables that will be accessed
         # but 'FLUSH TABLES WITH READ LOCK' creates deadlock
@@ -311,15 +293,7 @@ class Cursor(CursorInterface):
     def has_multirow_insert(self):
         return True
 
-    def limit_clause(self, select, limit=None, offset=None):
-        if offset and limit is None:
-            limit = 18446744073709551610  # max bigint
-        if limit is not None:
-            select += ' LIMIT %d' % limit
-        if offset is not None and offset != 0:
-            select += ' OFFSET %d' % offset
-        return select
-
-    def update_auto_increment(self, table, value):
-        self.cursor.execute('ALTER TABLE `%s` AUTO_INCREMENT = %%s' % table,
+    def update_auto_increment(self, connection, table, value):
+        cursor = connection.cursor()
+        cursor.execute('ALTER TABLE `%s` AUTO_INCREMENT = %%s' % table,
                 (value,))
diff --git a/trytond/backend/mysql/table.py b/trytond/backend/mysql/table.py
index 14b604d..a7bd9d2 100644
--- a/trytond/backend/mysql/table.py
+++ b/trytond/backend/mysql/table.py
@@ -1,6 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 
+from trytond.transaction import Transaction
 from trytond.backend.table import TableHandlerInterface
 import logging
 
@@ -9,159 +10,173 @@ logger = logging.getLogger(__name__)
 
 class TableHandler(TableHandlerInterface):
 
-    def __init__(self, cursor, model, module_name=None, history=False):
-        super(TableHandler, self).__init__(cursor, model,
+    def __init__(self, model, module_name=None, history=False):
+        super(TableHandler, self).__init__(model,
                 module_name=module_name, history=history)
         self._columns = {}
         self._constraints = []
         self._fkeys = []
         self._indexes = []
-        self._field2module = {}
         self._model = model
 
+        cursor = Transaction().connection.cursor()
         # Create new table if necessary
-        if not self.table_exist(self.cursor, self.table_name):
+        if not self.table_exist(self.table_name):
             if not self.history:
-                self.cursor.execute('CREATE TABLE `%s` ('
+                cursor.execute('CREATE TABLE `%s` ('
                     'id BIGINT AUTO_INCREMENT NOT NULL, '
                     'PRIMARY KEY(id)'
                     ') ENGINE=InnoDB;' % self.table_name)
             else:
-                self.cursor.execute('CREATE TABLE `%s` ('
+                cursor.execute('CREATE TABLE `%s` ('
                     '__id BIGINT AUTO_INCREMENT NOT NULL, '
                     'id BIGINT, '
                     'PRIMARY KEY(__id)'
                     ') ENGINE=InnoDB;' % self.table_name)
 
-        self._update_definitions()
+        self._update_definitions(columns=True)
         if 'id' not in self._columns:
             if not self.history:
-                self.cursor.execute('ALTER TABLE `%s` '
+                cursor.execute('ALTER TABLE `%s` '
                     'ADD COLUMN id BIGINT AUTO_INCREMENT '
                     'NOT NULL PRIMARY KEY' % self.table_name)
             else:
-                self.cursor.execute('ALTER TABLE `%s` '
+                cursor.execute('ALTER TABLE `%s` '
                     'ADD COLUMN id BIGINT' % self.table_name)
-            self._update_definitions()
+            self._update_definitions(columns=True)
         if self.history and '__id' not in self._columns:
-            self.cursor.execute('ALTER TABLE `%s` '
+            cursor.execute('ALTER TABLE `%s` '
                 'ADD COLUMN __id BIGINT AUTO_INCREMENT '
                 'NOT NULL PRIMARY KEY' % self.table_name)
         self._update_definitions()
 
     @staticmethod
-    def table_exist(cursor, table_name):
+    def table_exist(table_name):
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         cursor.execute("SELECT table_name FROM information_schema.tables "
             "WHERE table_schema = %s AND table_name = %s",
-            (cursor.database_name, table_name))
+            (transaction.database.name, table_name))
         return bool(cursor.rowcount)
 
     @staticmethod
-    def table_rename(cursor, old_name, new_name):
+    def table_rename(old_name, new_name):
+        cursor = Transaction().connection.cursor()
         # Rename table
-        if (TableHandler.table_exist(cursor, old_name)
-                and not TableHandler.table_exist(cursor, new_name)):
+        if (TableHandler.table_exist(old_name)
+                and not TableHandler.table_exist(new_name)):
             cursor.execute('ALTER TABLE `%s` RENAME TO `%s`'
                 % (old_name, new_name))
         # Rename history table
         old_history = old_name + '__history'
         new_history = new_name + '__history'
-        if (TableHandler.table_exist(cursor, old_history)
-                and not TableHandler.table_exist(cursor, new_history)):
+        if (TableHandler.table_exist(old_history)
+                and not TableHandler.table_exist(new_history)):
             cursor.execute('ALTER TABLE `%s` RENAME TO `%s`'
                 % (old_history, new_history))
 
     @staticmethod
-    def sequence_exist(cursor, sequence_name):
+    def sequence_exist(sequence_name):
         return True
 
     @staticmethod
-    def sequence_rename(cursor, old_name, new_name):
+    def sequence_rename(old_name, new_name):
         pass
 
     def column_exist(self, column_name):
         return column_name in self._columns
 
     def column_rename(self, old_name, new_name, exception=False):
+        cursor = Transaction().connection.cursor()
         if (self.column_exist(old_name)
                 and not self.column_exist(new_name)):
-            self.cursor.execute('ALTER TABLE `%s` '
+            cursor.execute('ALTER TABLE `%s` '
                 'RENAME COLUMN `%s` TO `%s`'
                 % (self.table_name, old_name, new_name))
-            self._update_definitions()
+            self._update_definitions(columns=True)
         elif exception and self.column_exist(new_name):
             raise Exception('Unable to rename column %s.%s to %s.%s: '
                 '%s.%s already exist!'
                 % (self.table_name, old_name, self.table_name, new_name,
                     self.table_name, new_name))
 
-    def _update_definitions(self):
-        # Fetch columns definitions from the table
-        self.cursor.execute("SELECT column_name, character_maximum_length, "
-                "data_type, is_nullable, column_default "
-            "FROM information_schema.columns "
-            "WHERE table_schema = %s AND table_name = %s",
-            (self.cursor.database_name, self.table_name))
-        self._columns = {}
-        for line in self.cursor.fetchall():
-            column, size, typname, nullable, default = line
-            self._columns[column] = {
-                'size': size,
-                'typname': typname,
-                'nullable': nullable == 'YES' and True or False,
-                'default': default,
-            }
-
-        # fetch constraints for the table
-        self.cursor.execute("SELECT constraint_name, constraint_type "
-            "FROM information_schema.table_constraints "
-            "WHERE table_schema = %s AND table_name = %s",
-            (self.cursor.database_name, self.table_name))
-        self._constraints = []
-        self._fkeys = []
-        for line in self.cursor.fetchall():
-            conname, contype = line
-            if contype not in ('PRIMARY KEY', 'FOREIGN KEY'):
-                self._constraints.append(conname)
-            elif contype == 'FOREIGN KEY':
-                self._fkeys.append(conname)
-
-        # Fetch indexes defined for the table
-        self.cursor.execute('SHOW INDEXES FROM `%s`' % self.table_name)
-        self._indexes = list(set(x[2] for x in self.cursor.fetchall()
-            if x[2] != 'PRIMARY'))
-
-        # Keep track of which module created each field
-        self._field2module = {}
-        if self.object_name is not None:
-            self.cursor.execute('SELECT f.name, f.module '
-                'FROM ir_model_field f '
-                'JOIN ir_model m on (f.model=m.id) '
-                'WHERE m.model = %s',
-                (self.object_name,))
-            for line in self.cursor.fetchall():
-                self._field2module[line[0]] = line[1]
+    def _update_definitions(self,
+            columns=None, constraints=None, indexes=None):
+        if columns is None and constraints is None and indexes is None:
+            columns = constraints = indexes = True
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
+        if columns:
+            # Fetch columns definitions from the table
+            cursor.execute("SELECT column_name, character_maximum_length, "
+                    "data_type, is_nullable, column_default "
+                "FROM information_schema.columns "
+                "WHERE table_schema = %s AND table_name = %s",
+                (transaction.database.name, self.table_name))
+            self._columns = {}
+            for line in cursor.fetchall():
+                column, size, typname, nullable, default = line
+                self._columns[column] = {
+                    'size': size,
+                    'typname': typname,
+                    'nullable': nullable == 'YES' and True or False,
+                    'default': default,
+                }
+
+        if constraints:
+            # fetch constraints for the table
+            cursor.execute("SELECT constraint_name, constraint_type "
+                "FROM information_schema.table_constraints "
+                "WHERE table_schema = %s AND table_name = %s",
+                (transaction.database.name, self.table_name))
+            self._constraints = []
+            self._fkeys = []
+            for line in cursor.fetchall():
+                conname, contype = line
+                if contype not in ('PRIMARY KEY', 'FOREIGN KEY'):
+                    self._constraints.append(conname)
+                elif contype == 'FOREIGN KEY':
+                    self._fkeys.append(conname)
+
+        if indexes:
+            # Fetch indexes defined for the table
+            cursor.execute('SHOW INDEXES FROM `%s`' % self.table_name)
+            self._indexes = list(set(x[2] for x in cursor.fetchall()
+                if x[2] != 'PRIMARY'))
+
+    @property
+    def _field2module(self):
+        cursor = Transaction().connection.cursor()
+        cursor.execute('SELECT f.name, f.module '
+            'FROM ir_model_field f '
+            'JOIN ir_model m on (f.model=m.id) '
+            'WHERE m.model = %s',
+            (self.object_name,))
+        return dict(cursor)
 
     def alter_size(self, column_name, column_type):
-        self.cursor.execute('ALTER TABLE `%s` '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE `%s` '
             'MODIFY COLUMN `%s` %s'
             % (self.table_name, column_name,
                 self._column_definition(column_name)))
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def alter_type(self, column_name, column_type):
-        self.cursor.execute('ALTER TABLE `%s` '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE `%s` '
             'MODIFY COLUMN `%s` %s'
             % (self.table_name, column_name,
                 self._column_definition(column_name, typname=column_type)))
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def db_default(self, column_name, value):
-        self.cursor.execute('ALTER TABLE `%s` '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE `%s` '
             'MODIFY COLUMN `%s` %s'
             % (self.table_name, column_name,
                 self._column_definition(column_name, default=value)))
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def add_raw_column(self, column_name, column_type, column_format,
             default_fun=None, field_size=None, migrate=True, string=''):
@@ -209,23 +224,24 @@ class TableHandler(TableHandlerInterface):
                         field_size)
             return
 
+        cursor = Transaction().connection.cursor()
         column_type = column_type[1]
-        self.cursor.execute('ALTER TABLE `%s` ADD COLUMN `%s` %s' %
+        cursor.execute('ALTER TABLE `%s` ADD COLUMN `%s` %s' %
                 (self.table_name, column_name, column_type))
 
         if column_format:
             # check if table is non-empty:
-            self.cursor.execute('SELECT 1 FROM `%s` limit 1' % self.table_name)
-            if self.cursor.rowcount:
+            cursor.execute('SELECT 1 FROM `%s` limit 1' % self.table_name)
+            if cursor.rowcount:
                 # Populate column with default values:
                 default = None
                 if default_fun is not None:
                     default = default_fun()
-                self.cursor.execute('UPDATE `' + self.table_name + '` '
+                cursor.execute('UPDATE `' + self.table_name + '` '
                     'SET `' + column_name + '` = %s',
                     (column_format(default),))
 
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def add_fk(self, column_name, reference, on_delete=None):
         if on_delete is None:
@@ -233,19 +249,22 @@ class TableHandler(TableHandlerInterface):
         conname = '%s_%s_fkey' % (self.table_name, column_name)
         if conname in self._fkeys:
             self.drop_fk(column_name)
-        self.cursor.execute('ALTER TABLE `%s` '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE `%s` '
             'ADD CONSTRAINT `%s` FOREIGN KEY (`%s`) '
             'REFERENCES `%s` (id) ON DELETE %s'
-            % (self.table_name, conname, column_name, reference, on_delete))
-        self._update_definitions()
+            % (self.table_name, conname, column_name, reference,
+                on_delete))
+        self._update_definitions(constraints=True)
 
     def drop_fk(self, column_name, table=None):
         conname = '%s_%s_fkey' % (self.table_name, column_name)
         if conname not in self._fkeys:
             return
-        self.cursor.execute('ALTER TABLE `%s` '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE `%s` '
             'DROP FOREIGN KEY `%s`' % (self.table_name, conname))
-        self._update_definitions()
+        self._update_definitions(constraints=True)
 
     def index_action(self, column_name, action='add', table=None):
         if isinstance(column_name, basestring):
@@ -260,123 +279,135 @@ class TableHandler(TableHandlerInterface):
                 if self._columns[k]['typname'] in ('text', 'blob'):
                     return
 
-        if action == 'add':
-            if index_name in self._indexes:
-                return
-            self.cursor.execute('CREATE INDEX `' + index_name + '` '
-                'ON `' + self.table_name + '` '
-                '( ' + ','.join(['`' + x + '`' for x in column_name]) + ')')
-            self._update_definitions()
-        elif action == 'remove':
-            if len(column_name) == 1:
-                if (self._field2module.get(column_name[0], self.module_name)
-                        != self.module_name):
+        with Transaction().connection.cursor() as cursor:
+            if action == 'add':
+                if index_name in self._indexes:
                     return
-
-            if index_name in self._indexes:
-                self.cursor.execute('DROP INDEX `%s` ON `%s`'
-                    % (index_name, self.table_name))
-                self._update_definitions()
-        else:
-            raise Exception('Index action not supported!')
+                cursor.execute('CREATE INDEX `' + index_name + '` '
+                    'ON `' + self.table_name
+                    + '` ( '
+                    + ','.join(['`' + x + '`' for x in column_name])
+                    + ')')
+                self._update_definitions(indexes=True)
+            elif action == 'remove':
+                if len(column_name) == 1:
+                    if (self._field2module.get(column_name[0],
+                                self.module_name) != self.module_name):
+                        return
+
+                if index_name in self._indexes:
+                    cursor.execute('DROP INDEX `%s` ON `%s`'
+                        % (index_name, self.table_name))
+                    self._update_definitions(indexes=True)
+            else:
+                raise Exception('Index action not supported!')
 
     def not_null_action(self, column_name, action='add'):
         if not self.column_exist(column_name):
             return
 
-        if action == 'add':
-            if not self._columns[column_name]['nullable']:
-                return
-            self.cursor.execute('SELECT id FROM `%s` '
-                'WHERE `%s` IS NULL'
-                % (self.table_name, column_name))
-            if not self.cursor.rowcount:
-                self.cursor.execute('ALTER TABLE `%s` '
+        with Transaction().connection.cursor() as cursor:
+            if action == 'add':
+                if not self._columns[column_name]['nullable']:
+                    return
+                cursor.execute('SELECT id FROM `%s` '
+                    'WHERE `%s` IS NULL'
+                    % (self.table_name, column_name))
+                if not cursor.rowcount:
+                    cursor.execute('ALTER TABLE `%s` '
+                        'MODIFY COLUMN `%s` %s'
+                        % (self.table_name, column_name,
+                            self._column_definition(column_name,
+                                nullable=False)))
+                    self._update_definitions(columns=True)
+                else:
+                    logger.warning(
+                        'Unable to set column %s '
+                        'of table %s not null !\n'
+                        'Try to re-run: '
+                        'trytond.py --update=module\n'
+                        'If it doesn\'t work, update records '
+                        'and execute manually:\n'
+                        'ALTER TABLE `%s` MODIFY COLUMN `%s` %s',
+                        column_name, self.table_name, self.table_name,
+                        column_name, self._column_definition(column_name,
+                            nullable=False))
+            elif action == 'remove':
+                if self._columns[column_name]['nullable']:
+                    return
+                if (self._field2module.get(column_name, self.module_name)
+                        != self.module_name):
+                    return
+                cursor.execute('ALTER TABLE `%s` '
                     'MODIFY COLUMN `%s` %s'
                     % (self.table_name, column_name,
-                        self._column_definition(column_name, nullable=False)))
-                self._update_definitions()
+                        self._column_definition(column_name, nullable=True)))
+                self._update_definitions(columns=True)
             else:
-                logger.warning(
-                    'Unable to set column %s '
-                    'of table %s not null !\n'
-                    'Try to re-run: '
-                    'trytond.py --update=module\n'
-                    'If it doesn\'t work, update records '
-                    'and execute manually:\n'
-                    'ALTER TABLE `%s` MODIFY COLUMN `%s` %s',
-                    column_name, self.table_name, self.table_name,
-                    column_name, self._column_definition(column_name,
-                        nullable=False))
-        elif action == 'remove':
-            if self._columns[column_name]['nullable']:
-                return
-            if (self._field2module.get(column_name, self.module_name)
-                    != self.module_name):
-                return
-            self.cursor.execute('ALTER TABLE `%s` '
-                'MODIFY COLUMN `%s` %s'
-                % (self.table_name, column_name,
-                    self._column_definition(column_name, nullable=True)))
-            self._update_definitions()
-        else:
-            raise Exception('Not null action not supported!')
+                raise Exception('Not null action not supported!')
 
     def add_constraint(self, ident, constraint, exception=False):
         ident = self.table_name + "_" + ident
         if ident in self._constraints:
             # This constrain already exists
             return
-        try:
-            self.cursor.execute('ALTER TABLE `%s` '
-                'ADD CONSTRAINT `%s` %s'
-                % (self.table_name, ident, constraint), constraint.params)
-        except Exception:
-            if exception:
-                raise
-            logger.warning(
-                'unable to add \'%s\' constraint on table %s !\n'
-                'If you want to have it, you should update the records '
-                'and execute manually:\n'
-                'ALTER table `%s` ADD CONSTRAINT `%s` %s',
-                constraint, self.table_name, self.table_name, ident,
-                constraint, exc_info=True)
-        self._update_definitions()
+
+        with Transaction().connection.cursor() as cursor:
+            try:
+                cursor.execute('ALTER TABLE `%s` '
+                    'ADD CONSTRAINT `%s` %s'
+                    % (self.table_name, ident, constraint), constraint.params)
+            except Exception:
+                if exception:
+                    raise
+                logger.warning(
+                    'unable to add \'%s\' constraint on table %s !\n'
+                    'If you want to have it, you should update the records '
+                    'and execute manually:\n'
+                    'ALTER table `%s` ADD CONSTRAINT `%s` %s',
+                    constraint, self.table_name, self.table_name, ident,
+                    constraint, exc_info=True)
+        self._update_definitions(constraints=True)
 
     def drop_constraint(self, ident, exception=False, table=None):
         ident = (table or self.table_name) + "_" + ident
         if ident not in self._constraints:
             return
-        try:
-            self.cursor.execute('ALTER TABLE `%s` '
-                'DROP CONSTRAINT `%s`'
-                % (self.table_name, ident))
-        except Exception:
-            if exception:
-                raise
-            logger.warning(
-                'unable to drop \'%s\' constraint on table %s!',
-                ident, self.table_name)
-        self._update_definitions()
+
+        with Transaction().connection.cursor() as cursor:
+            try:
+                cursor.execute('ALTER TABLE `%s` '
+                    'DROP CONSTRAINT `%s`'
+                    % (self.table_name, ident))
+            except Exception:
+                if exception:
+                    raise
+                logger.warning(
+                    'unable to drop \'%s\' constraint on table %s!',
+                    ident, self.table_name)
+        self._update_definitions(constraints=True)
 
     def drop_column(self, column_name, exception=False):
         if not self.column_exist(column_name):
             return
-        try:
-            self.cursor.execute(
-                'ALTER TABLE `%s` DROP COLUMN `%s`' %
-                (self.table_name, column_name))
-
-        except Exception:
-            if exception:
-                raise
-            logger.warning(
-                'unable to drop \'%s\' column on table %s!',
-                column_name, self.table_name)
-        self._update_definitions()
+
+        with Transaction().connection.cursor() as cursor:
+            try:
+                cursor.execute(
+                    'ALTER TABLE `%s` DROP COLUMN `%s`' %
+                    (self.table_name, column_name))
+
+            except Exception:
+                if exception:
+                    raise
+                logger.warning(
+                    'unable to drop \'%s\' column on table %s!',
+                    column_name, self.table_name)
+        self._update_definitions(columns=True)
 
     @staticmethod
-    def drop_table(cursor, model, table, cascade=False):
+    def drop_table(model, table, cascade=False):
+        cursor = Transaction().connection.cursor()
         cursor.execute('DELETE from ir_model_data where '
             'model = %s', model)
 
diff --git a/trytond/backend/postgresql/database.py b/trytond/backend/postgresql/database.py
index 3d7cf2d..505973a 100644
--- a/trytond/backend/postgresql/database.py
+++ b/trytond/backend/postgresql/database.py
@@ -12,6 +12,7 @@ try:
     compat.register()
 except ImportError:
     pass
+from psycopg2 import connect
 from psycopg2.pool import ThreadedConnectionPool
 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
@@ -26,11 +27,10 @@ from psycopg2 import OperationalError as DatabaseOperationalError
 
 from sql import Flavor
 
-from trytond.backend.database import DatabaseInterface, CursorInterface
+from trytond.backend.database import DatabaseInterface
 from trytond.config import config, parse_uri
 
-__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError',
-    'Cursor']
+__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
 
 logger = logging.getLogger(__name__)
 
@@ -60,34 +60,40 @@ class Database(DatabaseInterface):
     _version_cache = {}
     flavor = Flavor(ilike=True)
 
-    def __new__(cls, database_name='template1'):
-        if database_name in cls._databases:
-            return cls._databases[database_name]
-        return DatabaseInterface.__new__(cls, database_name=database_name)
+    def __new__(cls, name='template1'):
+        if name in cls._databases:
+            return cls._databases[name]
+        return DatabaseInterface.__new__(cls, name=name)
 
-    def __init__(self, database_name='template1'):
-        super(Database, self).__init__(database_name=database_name)
-        self._databases.setdefault(database_name, self)
+    def __init__(self, name='template1'):
+        super(Database, self).__init__(name=name)
+        self._databases.setdefault(name, self)
+        self._search_path = None
+        self._current_user = None
 
-    def connect(self):
-        if self._connpool is not None:
-            return self
-        logger.info('connect to "%s"', self.database_name)
+    @classmethod
+    def dsn(cls, name):
         uri = parse_uri(config.get('database', 'uri'))
         assert uri.scheme == 'postgresql'
         host = uri.hostname and "host=%s" % uri.hostname or ''
         port = uri.port and "port=%s" % uri.port or ''
-        name = "dbname=%s" % self.database_name
+        name = "dbname=%s" % name
         user = uri.username and "user=%s" % uri.username or ''
         password = ("password=%s" % urllib.unquote_plus(uri.password)
             if uri.password else '')
+        return '%s %s %s %s %s' % (host, port, name, user, password)
+
+    def connect(self):
+        if self._connpool is not None:
+            return self
+        logger.info('connect to "%s"', self.name)
         minconn = config.getint('database', 'minconn', default=1)
         maxconn = config.getint('database', 'maxconn', default=64)
-        dsn = '%s %s %s %s %s' % (host, port, name, user, password)
-        self._connpool = ThreadedConnectionPool(minconn, maxconn, dsn)
+        self._connpool = ThreadedConnectionPool(
+            minconn, maxconn, self.dsn(self.name))
         return self
 
-    def cursor(self, autocommit=False, readonly=False):
+    def get_connection(self, autocommit=False, readonly=False):
         if self._connpool is None:
             self.connect()
         conn = self._connpool.getconn()
@@ -95,10 +101,13 @@ class Database(DatabaseInterface):
             conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
         else:
             conn.set_isolation_level(ISOLATION_LEVEL_REPEATABLE_READ)
-        cursor = Cursor(self._connpool, conn, self)
         if readonly:
+            cursor = conn.cursor()
             cursor.execute('SET TRANSACTION READ ONLY')
-        return cursor
+        return conn
+
+    def put_connection(self, connection, close=False):
+        self._connpool.putconn(connection, close=close)
 
     def close(self):
         if self._connpool is None:
@@ -107,23 +116,26 @@ class Database(DatabaseInterface):
         self._connpool = None
 
     @classmethod
-    def create(cls, cursor, database_name):
+    def create(cls, connection, database_name):
+        cursor = connection.cursor()
         cursor.execute('CREATE DATABASE "' + database_name + '" '
             'TEMPLATE template0 ENCODING \'unicode\'')
+        connection.commit()
         cls._list_cache = None
 
-    @classmethod
-    def drop(cls, cursor, database_name):
+    def drop(self, connection, database_name):
+        cursor = connection.cursor()
         cursor.execute('DROP DATABASE "' + database_name + '"')
-        cls._list_cache = None
+        Database._list_cache = None
 
-    def get_version(self, cursor):
-        if self.database_name not in self._version_cache:
+    def get_version(self, connection):
+        if self.name not in self._version_cache:
+            cursor = connection.cursor()
             cursor.execute('SELECT version()')
             version, = cursor.fetchone()
-            self._version_cache[self.database_name] = tuple(map(int,
+            self._version_cache[self.name] = tuple(map(int,
                 RE_VERSION.search(version).groups()))
-        return self._version_cache[self.database_name]
+        return self._version_cache[self.name]
 
     @staticmethod
     def dump(database_name):
@@ -158,10 +170,8 @@ class Database(DatabaseInterface):
         from trytond.tools import exec_command_pipe
 
         database = Database().connect()
-        cursor = database.cursor(autocommit=True)
-        database.create(cursor, database_name)
-        cursor.commit()
-        cursor.close()
+        connection = database.get_connection(autocommit=True)
+        database.create(connection, database_name)
         database.close()
 
         cmd = ['pg_restore', '--no-owner']
@@ -195,8 +205,8 @@ class Database(DatabaseInterface):
             raise Exception('Couldn\'t restore database')
 
         database = Database(database_name).connect()
-        cursor = database.cursor()
-        if not cursor.test():
+        cursor = database.get_connection().cursor()
+        if not database.test():
             cursor.close()
             database.close()
             raise Exception('Couldn\'t restore database!')
@@ -205,43 +215,43 @@ class Database(DatabaseInterface):
         Database._list_cache = None
         return True
 
-    @staticmethod
-    def list(cursor):
+    def list(self):
         now = time.time()
         timeout = config.getint('session', 'timeout')
         res = Database._list_cache
         if res and abs(Database._list_cache_timestamp - now) < timeout:
             return res
+
+        connection = self.get_connection()
+        cursor = connection.cursor()
         cursor.execute('SELECT datname FROM pg_database '
             'WHERE datistemplate = false ORDER BY datname')
         res = []
-        for db_name, in cursor.fetchall():
-            db_name = db_name.encode('utf-8')
+        for db_name, in cursor:
             try:
-                database = Database(db_name).connect()
+                with connect(self.dsn(db_name)) as conn:
+                    if self._test(conn):
+                        res.append(db_name)
             except Exception:
                 continue
-            cursor2 = database.cursor()
-            if cursor2.test():
-                res.append(db_name)
-                cursor2.close(close=True)
-            else:
-                cursor2.close(close=True)
-                database.close()
+        self.put_connection(connection)
+
         Database._list_cache = res
         Database._list_cache_timestamp = now
         return res
 
-    @staticmethod
-    def init(cursor):
+    def init(self):
         from trytond.modules import get_module_info
+
+        connection = self.get_connection()
+        cursor = connection.cursor()
         sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
         with open(sql_file) as fp:
             for line in fp.read().split(';'):
                 if (len(line) > 0) and (not line.isspace()):
                     cursor.execute(line)
 
-        for module in ('ir', 'res', 'webdav'):
+        for module in ('ir', 'res'):
             state = 'uninstalled'
             if module in ('ir', 'res'):
                 state = 'to install'
@@ -258,115 +268,89 @@ class Database(DatabaseInterface):
                     'VALUES (%s, now(), %s, %s)',
                     (0, module_id, dependency))
 
-
-class Cursor(CursorInterface):
-
-    def __init__(self, connpool, conn, database):
-        super(Cursor, self).__init__()
-        self._connpool = connpool
-        self._conn = conn
-        self._database = database
-        self._current_user = None
-        self._search_path = None
-        self.cursor = conn.cursor()
-        self.commit()
-        self.sql_from_log = {}
-        self.sql_into_log = {}
-        self.count = {
-            'from': 0,
-            'into': 0,
-        }
-
-    @property
-    def database_name(self):
-        return self._database.database_name
-
-    # TODO to remove
-    @property
-    def dbname(self):
-        return self.database_name
-
-    def __getattr__(self, name):
-        return getattr(self.cursor, name)
-
-    def execute(self, sql, params=None):
-        if params:
-            return self.cursor.execute(sql, params)
-        else:
-            return self.cursor.execute(sql)
-
-    def close(self, close=False):
-        self.cursor.close()
-        self.rollback()
-        self._connpool.putconn(self._conn, close=close)
-
-    def commit(self):
-        super(Cursor, self).commit()
-        self._conn.commit()
-
-    def rollback(self):
-        super(Cursor, self).rollback()
-        self._conn.rollback()
+        connection.commit()
+        self.put_connection(connection)
 
     def test(self):
-        self.cursor.execute('SELECT 1 FROM information_schema.tables '
+        connection = self.get_connection()
+        is_tryton_database = self._test(connection)
+        self.put_connection(connection)
+        return is_tryton_database
+
+    @classmethod
+    def _test(cls, connection):
+        cursor = connection.cursor()
+        cursor.execute('SELECT 1 FROM information_schema.tables '
             'WHERE table_name IN %s',
             (('ir_model', 'ir_model_field', 'ir_ui_view', 'ir_ui_menu',
                     'res_user', 'res_group', 'ir_module',
-                    'ir_module_dependency', 'ir_translation', 'ir_lang'),))
-        return len(self.cursor.fetchall()) != 0
+                    'ir_module_dependency', 'ir_translation',
+                    'ir_lang'),))
+        return len(cursor.fetchall()) != 0
 
-    def nextid(self, table):
-        self.cursor.execute("SELECT NEXTVAL('" + table + "_id_seq')")
-        return self.cursor.fetchone()[0]
+    def nextid(self, connection, table):
+        cursor = connection.cursor()
+        cursor.execute("SELECT NEXTVAL('" + table + "_id_seq')")
+        return cursor.fetchone()[0]
 
-    def setnextid(self, table, value):
-        self.cursor.execute("SELECT SETVAL('" + table + "_id_seq', %d)"
-            % value)
+    def setnextid(self, connection, table, value):
+        cursor = connection.cursor()
+        cursor.execute("SELECT SETVAL('" + table + "_id_seq', %d)" % value)
 
-    def currid(self, table):
-        self.cursor.execute('SELECT last_value FROM "' + table + '_id_seq"')
-        return self.cursor.fetchone()[0]
+    def currid(self, connection, table):
+        cursor = connection.cursor()
+        cursor.execute('SELECT last_value FROM "' + table + '_id_seq"')
+        return cursor.fetchone()[0]
 
-    def lock(self, table):
-        self.cursor.execute('LOCK "%s" IN EXCLUSIVE MODE NOWAIT' % table)
+    def lock(self, connection, table):
+        cursor = connection.cursor()
+        cursor.execute('LOCK "%s" IN EXCLUSIVE MODE NOWAIT' % table)
 
     def has_constraint(self):
         return True
 
-    def limit_clause(self, select, limit=None, offset=None):
-        if limit is not None:
-            select += ' LIMIT %d' % limit
-        if offset is not None and offset != 0:
-            select += ' OFFSET %d' % offset
-        return select
-
-    def has_returning(self):
-        # RETURNING clause is available since PostgreSQL 8.2
-        return self._database.get_version(self) >= (8, 2)
-
     def has_multirow_insert(self):
         return True
 
+    def get_table_schema(self, connection, table_name):
+        cursor = connection.cursor()
+        for schema in self.search_path:
+            cursor.execute('SELECT 1 '
+                'FROM information_schema.tables '
+                'WHERE table_name = %s AND table_schema = %s',
+                (table_name, schema))
+            if cursor.rowcount:
+                return schema
+
     @property
     def current_user(self):
         if self._current_user is None:
-            self.execute('SELECT current_user')
-            self._current_user, = self.fetchone()
+            connection = self.get_connection()
+            try:
+                cursor = connection.cursor()
+                cursor.execute('SELECT current_user')
+                self._current_user = cursor.fetchone()[0]
+            finally:
+                self.put_connection(connection)
         return self._current_user
 
     @property
     def search_path(self):
         if self._search_path is None:
-            self.execute('SHOW search_path')
-            path, = self.fetchone()
-            special_values = {
-                'user': self.current_user,
-            }
-            self._search_path = [
-                unescape_quote(replace_special_values(
-                        p.strip(), **special_values))
-                for p in path.split(',')]
+            connection = self.get_connection()
+            try:
+                cursor = connection.cursor()
+                cursor.execute('SHOW search_path')
+                path, = cursor.fetchone()
+                special_values = {
+                    'user': self.current_user,
+                }
+                self._search_path = [
+                    unescape_quote(replace_special_values(
+                            p.strip(), **special_values))
+                    for p in path.split(',')]
+            finally:
+                self.put_connection(connection)
         return self._search_path
 
 register_type(UNICODE)
diff --git a/trytond/backend/postgresql/table.py b/trytond/backend/postgresql/table.py
index 932481c..f5c70ad 100644
--- a/trytond/backend/postgresql/table.py
+++ b/trytond/backend/postgresql/table.py
@@ -1,6 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-
+from trytond.transaction import Transaction
 from trytond.backend.table import TableHandlerInterface
 import logging
 
@@ -11,102 +11,99 @@ logger = logging.getLogger(__name__)
 
 class TableHandler(TableHandlerInterface):
 
-    def __init__(self, cursor, model, module_name=None, history=False):
-        super(TableHandler, self).__init__(cursor, model,
+    def __init__(self, model, module_name=None, history=False):
+        super(TableHandler, self).__init__(model,
                 module_name=module_name, history=history)
         self._columns = {}
         self._constraints = []
         self._fk_deltypes = {}
         self._indexes = []
-        self._field2module = {}
 
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         # Create sequence if necessary
-        if not self.sequence_exist(self.cursor, self.sequence_name):
-            self.cursor.execute('CREATE SEQUENCE "%s"' % self.sequence_name)
+        if not self.sequence_exist(self.sequence_name):
+            cursor.execute('CREATE SEQUENCE "%s"' % self.sequence_name)
 
         # Create new table if necessary
-        if not self.table_exist(self.cursor, self.table_name):
-            self.cursor.execute('CREATE TABLE "%s" ()' % self.table_name)
-        self.table_schema = self.get_table_schema(self.cursor, self.table_name)
+        if not self.table_exist(self.table_name):
+            cursor.execute('CREATE TABLE "%s" ()' % self.table_name)
+        self.table_schema = transaction.database.get_table_schema(
+            transaction.connection, self.table_name)
 
-        self.cursor.execute('SELECT tableowner = current_user FROM pg_tables '
+        cursor.execute('SELECT tableowner = current_user FROM pg_tables '
             'WHERE tablename = %s AND schemaname = %s',
             (self.table_name, self.table_schema))
-        self.is_owner, = self.cursor.fetchone()
+        self.is_owner, = cursor.fetchone()
 
         if model.__doc__ and self.is_owner:
-            self.cursor.execute('COMMENT ON TABLE "%s" IS \'%s\'' %
+            cursor.execute('COMMENT ON TABLE "%s" IS \'%s\'' %
                 (self.table_name, model.__doc__.replace("'", "''")))
 
-        self._update_definitions()
+        self._update_definitions(columns=True)
         if 'id' not in self._columns:
             if not self.history:
-                self.cursor.execute('ALTER TABLE "%s" '
+                cursor.execute('ALTER TABLE "%s" '
                     'ADD COLUMN id INTEGER '
                     'DEFAULT nextval(\'"%s"\') NOT NULL'
                     % (self.table_name, self.sequence_name))
-                self.cursor.execute('ALTER TABLE "%s" '
+                cursor.execute('ALTER TABLE "%s" '
                     'ADD PRIMARY KEY(id)' % self.table_name)
             else:
-                self.cursor.execute('ALTER TABLE "%s" '
+                cursor.execute('ALTER TABLE "%s" '
                     'ADD COLUMN id INTEGER' % self.table_name)
-            self._update_definitions()
+            self._update_definitions(columns=True)
         if self.history and '__id' not in self._columns:
-            self.cursor.execute('ALTER TABLE "%s" '
+            cursor.execute('ALTER TABLE "%s" '
                 'ADD COLUMN __id INTEGER '
                 'DEFAULT nextval(\'"%s"\') NOT NULL' %
                 (self.table_name, self.sequence_name))
-            self.cursor.execute('ALTER TABLE "%s" '
+            cursor.execute('ALTER TABLE "%s" '
                 'ADD PRIMARY KEY(__id)' % self.table_name)
         else:
             default = "nextval('%s'::regclass)" % self.sequence_name
             if self.history:
                 if self._columns['__id']['default'] != default:
-                    self.cursor.execute('ALTER TABLE "%s" '
+                    cursor.execute('ALTER TABLE "%s" '
                         'ALTER __id SET DEFAULT %s'
                         % (self.table_name, default))
             if self._columns['id']['default'] != default:
-                    self.cursor.execute('ALTER TABLE "%s" '
+                    cursor.execute('ALTER TABLE "%s" '
                         'ALTER id SET DEFAULT %s'
                         % (self.table_name, default))
         self._update_definitions()
 
-    @classmethod
-    def get_table_schema(cls, cursor, table_name):
-        for schema in cursor.search_path:
-            cursor.execute('SELECT 1 '
-                'FROM information_schema.tables '
-                'WHERE table_name = %s AND table_schema = %s',
-                (table_name, schema))
-            if cursor.rowcount:
-                return schema
-
-    @classmethod
-    def table_exist(cls, cursor, table_name):
-        return bool(cls.get_table_schema(cursor, table_name))
+    @staticmethod
+    def table_exist(table_name):
+        transaction = Transaction()
+        return bool(transaction.database.get_table_schema(
+                transaction.connection, table_name))
 
     @staticmethod
-    def table_rename(cursor, old_name, new_name):
+    def table_rename(old_name, new_name):
+        cursor = Transaction().connection.cursor()
         # Rename table
-        if (TableHandler.table_exist(cursor, old_name)
-                and not TableHandler.table_exist(cursor, new_name)):
+        if (TableHandler.table_exist(old_name)
+                and not TableHandler.table_exist(new_name)):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_name, new_name))
         # Rename sequence
         old_sequence = old_name + '_id_seq'
         new_sequence = new_name + '_id_seq'
-        TableHandler.sequence_rename(cursor, old_sequence, new_sequence)
+        TableHandler.sequence_rename(old_sequence, new_sequence)
         # Rename history table
         old_history = old_name + "__history"
         new_history = new_name + "__history"
-        if (TableHandler.table_exist(cursor, old_history)
-                and not TableHandler.table_exist(cursor, new_history)):
+        if (TableHandler.table_exist(old_history)
+                and not TableHandler.table_exist(new_history)):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_history, new_history))
 
     @classmethod
-    def sequence_schema(cls, cursor, sequence_name):
-        for schema in cursor.search_path:
+    def sequence_schema(cls, sequence_name):
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
+        for schema in transaction.database.search_path:
             cursor.execute('SELECT 1 '
                 'FROM information_schema.sequences '
                 'WHERE sequence_name = %s AND sequence_schema = %s',
@@ -115,13 +112,14 @@ class TableHandler(TableHandlerInterface):
                 return schema
 
     @classmethod
-    def sequence_exist(cls, cursor, sequence_name):
-        return bool(cls.sequence_schema(cursor, sequence_name))
+    def sequence_exist(cls, sequence_name):
+        return bool(cls.sequence_schema(sequence_name))
 
     @staticmethod
-    def sequence_rename(cursor, old_name, new_name):
-        if (TableHandler.sequence_exist(cursor, old_name)
-                and not TableHandler.sequence_exist(cursor, new_name)):
+    def sequence_rename(old_name, new_name):
+        cursor = Transaction().connection.cursor()
+        if (TableHandler.sequence_exist(old_name)
+                and not TableHandler.sequence_exist(new_name)):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_name, new_name))
 
@@ -129,92 +127,101 @@ class TableHandler(TableHandlerInterface):
         return column_name in self._columns
 
     def column_rename(self, old_name, new_name, exception=False):
+        cursor = Transaction().connection.cursor()
         if (self.column_exist(old_name)
                 and not self.column_exist(new_name)):
-            self.cursor.execute('ALTER TABLE "%s" '
+            cursor.execute('ALTER TABLE "%s" '
                 'RENAME COLUMN "%s" TO "%s"'
                 % (self.table_name, old_name, new_name))
-            self._update_definitions()
+            self._update_definitions(columns=True)
         elif exception and self.column_exist(new_name):
             raise Exception('Unable to rename column %s.%s to %s.%s: '
                 '%s.%s already exist!'
                 % (self.table_name, old_name, self.table_name, new_name,
                     self.table_name, new_name))
 
-    def _update_definitions(self):
-        self._columns = {}
-        # Fetch columns definitions from the table
-        self.cursor.execute('SELECT '
-            'column_name, udt_name, is_nullable, character_maximum_length, '
-            'column_default '
-            'FROM information_schema.columns '
-            'WHERE table_name = %s AND table_schema = %s',
-            (self.table_name, self.table_schema))
-        for column, typname, nullable, size, default in self.cursor.fetchall():
-            self._columns[column] = {
-                'typname': typname,
-                'notnull': True if nullable == 'NO' else False,
-                'size': size,
-                'default': default,
-                }
-
-        # fetch constraints for the table
-        self.cursor.execute('SELECT constraint_name '
-            'FROM information_schema.table_constraints '
-            'WHERE table_name = %s AND table_schema = %s',
-            (self.table_name, self.table_schema))
-        self._constraints = [c for c, in self.cursor.fetchall()]
-
-        self.cursor.execute('SELECT k.column_name, r.delete_rule '
-            'FROM information_schema.key_column_usage AS k '
-            'JOIN information_schema.referential_constraints AS r '
-            'ON r.constraint_schema = k.constraint_schema '
-            'AND r.constraint_name = k.constraint_name '
-            'WHERE k.table_name = %s AND k.table_schema = %s',
-            (self.table_name, self.table_schema))
-        self._fk_deltypes = dict(self.cursor.fetchall())
-
-        # Fetch indexes defined for the table
-        self.cursor.execute("SELECT cl2.relname "
-            "FROM pg_index ind "
-                "JOIN pg_class cl on (cl.oid = ind.indrelid) "
-                "JOIN pg_namespace n ON (cl.relnamespace = n.oid) "
-                "JOIN pg_class cl2 on (cl2.oid = ind.indexrelid) "
-            "WHERE cl.relname = %s AND n.nspname = %s",
-            (self.table_name, self.table_schema))
-        self._indexes = [l[0] for l in self.cursor.fetchall()]
-
-        # Keep track of which module created each field
-        self._field2module = {}
-        if self.object_name is not None:
-            self.cursor.execute('SELECT f.name, f.module '
-                'FROM ir_model_field f '
-                    'JOIN ir_model m on (f.model=m.id) '
-                'WHERE m.model = %s',
-                (self.object_name,))
-            for line in self.cursor.fetchall():
-                self._field2module[line[0]] = line[1]
+    def _update_definitions(self,
+            columns=None, constraints=None, indexes=None):
+        if columns is None and constraints is None and indexes is None:
+            columns = constraints = indexes = True
+        cursor = Transaction().connection.cursor()
+        if columns:
+            self._columns = {}
+            # Fetch columns definitions from the table
+            cursor.execute('SELECT '
+                'column_name, udt_name, is_nullable, '
+                'character_maximum_length, '
+                'column_default '
+                'FROM information_schema.columns '
+                'WHERE table_name = %s AND table_schema = %s',
+                (self.table_name, self.table_schema))
+            for column, typname, nullable, size, default in cursor.fetchall():
+                self._columns[column] = {
+                    'typname': typname,
+                    'notnull': True if nullable == 'NO' else False,
+                    'size': size,
+                    'default': default,
+                    }
+
+        if constraints:
+            # fetch constraints for the table
+            cursor.execute('SELECT constraint_name '
+                'FROM information_schema.table_constraints '
+                'WHERE table_name = %s AND table_schema = %s',
+                (self.table_name, self.table_schema))
+            self._constraints = [c for c, in cursor.fetchall()]
+
+            cursor.execute('SELECT k.column_name, r.delete_rule '
+                'FROM information_schema.key_column_usage AS k '
+                'JOIN information_schema.referential_constraints AS r '
+                'ON r.constraint_schema = k.constraint_schema '
+                'AND r.constraint_name = k.constraint_name '
+                'WHERE k.table_name = %s AND k.table_schema = %s',
+                (self.table_name, self.table_schema))
+            self._fk_deltypes = dict(cursor.fetchall())
+
+        if indexes:
+            # Fetch indexes defined for the table
+            cursor.execute("SELECT cl2.relname "
+                "FROM pg_index ind "
+                    "JOIN pg_class cl on (cl.oid = ind.indrelid) "
+                    "JOIN pg_namespace n ON (cl.relnamespace = n.oid) "
+                    "JOIN pg_class cl2 on (cl2.oid = ind.indexrelid) "
+                "WHERE cl.relname = %s AND n.nspname = %s",
+                (self.table_name, self.table_schema))
+            self._indexes = [l[0] for l in cursor.fetchall()]
+
+    @property
+    def _field2module(self):
+        cursor = Transaction().connection.cursor()
+        cursor.execute('SELECT f.name, f.module '
+            'FROM ir_model_field f '
+                'JOIN ir_model m on (f.model=m.id) '
+            'WHERE m.model = %s',
+            (self.object_name,))
+        return dict(cursor)
 
     def alter_size(self, column_name, column_type):
-
-        self.cursor.execute("ALTER TABLE \"%s\" "
+        cursor = Transaction().connection.cursor()
+        cursor.execute("ALTER TABLE \"%s\" "
             "RENAME COLUMN \"%s\" TO _temp_change_size"
             % (self.table_name, column_name))
-        self.cursor.execute("ALTER TABLE \"%s\" "
+        cursor.execute("ALTER TABLE \"%s\" "
             "ADD COLUMN \"%s\" %s"
             % (self.table_name, column_name, column_type))
-        self.cursor.execute("UPDATE \"%s\" "
+        cursor.execute("UPDATE \"%s\" "
             "SET \"%s\" = _temp_change_size::%s"
             % (self.table_name, column_name, column_type))
-        self.cursor.execute("ALTER TABLE \"%s\" "
+        cursor.execute("ALTER TABLE \"%s\" "
             "DROP COLUMN _temp_change_size"
             % (self.table_name,))
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def alter_type(self, column_name, column_type):
-        self.cursor.execute('ALTER TABLE "' + self.table_name + '" '
+        cursor = Transaction().connection.cursor()
+        cursor.execute('ALTER TABLE "' + self.table_name + '" '
             'ALTER "' + column_name + '" TYPE ' + column_type)
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def db_default(self, column_name, value):
         if value in [True, False]:
@@ -222,21 +229,24 @@ class TableHandler(TableHandlerInterface):
         else:
             test = value
         if self._columns[column_name]['default'] != test:
-            self.cursor.execute('ALTER TABLE "' + self.table_name + '" '
+            cursor = Transaction().connection.cursor()
+            cursor.execute('ALTER TABLE "' + self.table_name + '" '
                 'ALTER COLUMN "' + column_name + '" SET DEFAULT %s',
                 (value,))
 
     def add_raw_column(self, column_name, column_type, column_format,
             default_fun=None, field_size=None, migrate=True, string=''):
+        cursor = Transaction().connection.cursor()
+
         def comment():
             if self.is_owner:
-                self.cursor.execute('COMMENT ON COLUMN "%s"."%s" IS \'%s\'' %
+                cursor.execute('COMMENT ON COLUMN "%s"."%s" IS \'%s\'' %
                     (self.table_name, column_name, string.replace("'", "''")))
         if self.column_exist(column_name):
             if (column_name in ('create_date', 'write_date')
                     and column_type[1].lower() != 'timestamp(6)'):
                 # Migrate dates from timestamp(0) to timestamp
-                self.cursor.execute('ALTER TABLE "' + self.table_name + '" '
+                cursor.execute('ALTER TABLE "' + self.table_name + '" '
                     'ALTER COLUMN "' + column_name + '" TYPE timestamp')
             comment()
             if not migrate:
@@ -261,11 +271,11 @@ class TableHandler(TableHandlerInterface):
                     and self._columns[column_name]['typname'] == 'varchar'):
                 # Migrate size
                 if field_size is None:
-                    if self._columns[column_name]['size'] > 0:
+                    if self._columns[column_name]['size']:
                         self.alter_size(column_name, base_type)
                 elif self._columns[column_name]['size'] == field_size:
                     pass
-                elif (self._columns[column_name]['size'] > 0
+                elif (self._columns[column_name]['size']
                         and self._columns[column_name]['size'] < field_size):
                     self.alter_size(column_name, column_type[1])
                 else:
@@ -279,23 +289,23 @@ class TableHandler(TableHandlerInterface):
             return
 
         column_type = column_type[1]
-        self.cursor.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s'
+        cursor.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s'
             % (self.table_name, column_name, column_type))
         comment()
 
         if column_format:
             # check if table is non-empty:
-            self.cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
-            if self.cursor.rowcount:
+            cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
+            if cursor.rowcount:
                 # Populate column with default values:
                 default = None
                 if default_fun is not None:
                     default = default_fun()
-                self.cursor.execute('UPDATE "' + self.table_name + '" '
+                cursor.execute('UPDATE "' + self.table_name + '" '
                     'SET "' + column_name + '" = %s',
                     (column_format(default),))
 
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def add_fk(self, column_name, reference, on_delete=None):
         if on_delete is not None:
@@ -303,25 +313,26 @@ class TableHandler(TableHandlerInterface):
         else:
             on_delete = 'SET NULL'
 
+        cursor = Transaction().connection.cursor()
         name = self.table_name + '_' + column_name + '_fkey'
-        self.cursor.execute('SELECT 1 '
+        cursor.execute('SELECT 1 '
             'FROM information_schema.key_column_usage '
             'WHERE table_name = %s AND table_schema = %s '
             'AND constraint_name = %s',
             (self.table_name, self.table_schema, name))
         add = False
-        if not self.cursor.rowcount:
+        if not cursor.rowcount:
             add = True
         elif self._fk_deltypes.get(column_name) != on_delete:
             self.drop_fk(column_name)
             add = True
         if add:
-            self.cursor.execute('ALTER TABLE "' + self.table_name + '" '
+            cursor.execute('ALTER TABLE "' + self.table_name + '" '
                 'ADD CONSTRAINT "' + name + '" '
                 'FOREIGN KEY ("' + column_name + '") '
                 'REFERENCES "' + reference + '" '
                 'ON DELETE ' + on_delete)
-        self._update_definitions()
+        self._update_definitions(constraints=True)
 
     def drop_fk(self, column_name, table=None):
         self.drop_constraint(column_name + '_fkey', table=table)
@@ -336,69 +347,73 @@ class TableHandler(TableHandlerInterface):
         else:
             test_index_name = index_name
 
-        if action == 'add':
-            if test_index_name in self._indexes:
-                return
-            self.cursor.execute('CREATE INDEX "' + index_name + '" '
-                'ON "' + self.table_name + '" ( '
-                    + ','.join(['"' + x + '"' for x in column_name]) + ')')
-            self._update_definitions()
-        elif action == 'remove':
-            if len(column_name) == 1:
-                if (self._field2module.get(column_name[0], self.module_name)
-                        != self.module_name):
+        with Transaction().connection.cursor() as cursor:
+            if action == 'add':
+                if test_index_name in self._indexes:
                     return
-
-            if test_index_name in self._indexes:
-                self.cursor.execute('DROP INDEX "%s" ' % (index_name,))
-                self._update_definitions()
-        else:
-            raise Exception('Index action not supported!')
+                cursor.execute('CREATE INDEX "' + index_name + '" '
+                    'ON "' + self.table_name + '" ( '
+                        + ','.join(['"' + x + '"' for x in column_name]) + ')')
+                self._update_definitions(indexes=True)
+            elif action == 'remove':
+                if len(column_name) == 1:
+                    if (self._field2module.get(column_name[0],
+                                self.module_name) != self.module_name):
+                        return
+
+                if test_index_name in self._indexes:
+                    cursor.execute('DROP INDEX "%s" ' % (index_name,))
+                    self._update_definitions(indexes=True)
+            else:
+                raise Exception('Index action not supported!')
 
     def not_null_action(self, column_name, action='add'):
         if not self.column_exist(column_name):
             return
 
-        if action == 'add':
-            if self._columns[column_name]['notnull']:
-                return
-            self.cursor.execute('SELECT id FROM "%s" '
-                'WHERE "%s" IS NULL'
-                % (self.table_name, column_name))
-            if not self.cursor.rowcount:
-                self.cursor.execute('ALTER TABLE "' + self.table_name + '" '
-                    'ALTER COLUMN "' + column_name + '" SET NOT NULL')
-                self._update_definitions()
+        with Transaction().connection.cursor() as cursor:
+            if action == 'add':
+                if self._columns[column_name]['notnull']:
+                    return
+                cursor.execute('SELECT id FROM "%s" '
+                    'WHERE "%s" IS NULL'
+                    % (self.table_name, column_name))
+                if not cursor.rowcount:
+                    cursor.execute('ALTER TABLE "' + self.table_name + '" '
+                        'ALTER COLUMN "' + column_name + '" SET NOT NULL')
+                    self._update_definitions(columns=True)
+                else:
+                    logger.warning(
+                        'Unable to set column %s '
+                        'of table %s not null !\n'
+                        'Try to re-run: '
+                        'trytond.py --update=module\n'
+                        'If it doesn\'t work, update records '
+                        'and execute manually:\n'
+                        'ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL',
+                        column_name, self.table_name, self.table_name,
+                        column_name)
+            elif action == 'remove':
+                if not self._columns[column_name]['notnull']:
+                    return
+                if (self._field2module.get(column_name, self.module_name)
+                        != self.module_name):
+                    return
+                cursor.execute('ALTER TABLE "%s" '
+                    'ALTER COLUMN "%s" DROP NOT NULL'
+                    % (self.table_name, column_name))
+                self._update_definitions(columns=True)
             else:
-                logger.warning(
-                    'Unable to set column %s '
-                    'of table %s not null !\n'
-                    'Try to re-run: '
-                    'trytond.py --update=module\n'
-                    'If it doesn\'t work, update records '
-                    'and execute manually:\n'
-                    'ALTER TABLE "%s" ALTER COLUMN "%s" SET NOT NULL',
-                    column_name, self.table_name, self.table_name, column_name)
-        elif action == 'remove':
-            if not self._columns[column_name]['notnull']:
-                return
-            if (self._field2module.get(column_name, self.module_name)
-                    != self.module_name):
-                return
-            self.cursor.execute('ALTER TABLE "%s" '
-                'ALTER COLUMN "%s" DROP NOT NULL'
-                % (self.table_name, column_name))
-            self._update_definitions()
-        else:
-            raise Exception('Not null action not supported!')
+                raise Exception('Not null action not supported!')
 
     def add_constraint(self, ident, constraint, exception=False):
         ident = self.table_name + "_" + ident
         if ident in self._constraints:
             # This constrain already exist
             return
+        cursor = Transaction().connection.cursor()
         try:
-            self.cursor.execute('ALTER TABLE "%s" '
+            cursor.execute('ALTER TABLE "%s" '
                 'ADD CONSTRAINT "%s" %s'
                 % (self.table_name, ident, constraint), constraint.params)
         except Exception:
@@ -411,14 +426,15 @@ class TableHandler(TableHandlerInterface):
                 'ALTER table "%s" ADD CONSTRAINT "%s" %s',
                 constraint, self.table_name, self.table_name, ident,
                 constraint)
-        self._update_definitions()
+        self._update_definitions(constraints=True)
 
     def drop_constraint(self, ident, exception=False, table=None):
         ident = (table or self.table_name) + "_" + ident
         if ident not in self._constraints:
             return
+        cursor = Transaction().connection.cursor()
         try:
-            self.cursor.execute('ALTER TABLE "%s" '
+            cursor.execute('ALTER TABLE "%s" '
                 'DROP CONSTRAINT "%s"'
                 % (self.table_name, ident))
         except Exception:
@@ -427,13 +443,14 @@ class TableHandler(TableHandlerInterface):
             logger.warning(
                 'unable to drop \'%s\' constraint on table %s!',
                 ident, self.table_name)
-        self._update_definitions()
+        self._update_definitions(constraints=True)
 
     def drop_column(self, column_name, exception=False):
         if not self.column_exist(column_name):
             return
+        cursor = Transaction().connection.cursor()
         try:
-            self.cursor.execute(
+            cursor.execute(
                 'ALTER TABLE "%s" DROP COLUMN "%s"' %
                 (self.table_name, column_name))
 
@@ -443,10 +460,11 @@ class TableHandler(TableHandlerInterface):
             logger.warning(
                 'unable to drop \'%s\' column on table %s!',
                 column_name, self.table_name, exc_info=True)
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     @staticmethod
-    def drop_table(cursor, model, table, cascade=False):
+    def drop_table(model, table, cascade=False):
+        cursor = Transaction().connection.cursor()
         cursor.execute('DELETE FROM ir_model_data '
             'WHERE model = \'%s\'' % model)
 
diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py
index 91346b0..ff5a91a 100644
--- a/trytond/backend/sqlite/database.py
+++ b/trytond/backend/sqlite/database.py
@@ -1,6 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.backend.database import DatabaseInterface, CursorInterface
+from trytond.backend.database import DatabaseInterface
 from trytond.config import config
 import os
 from decimal import Decimal
@@ -24,8 +24,7 @@ from sql import Flavor, Table
 from sql.functions import (Function, Extract, Position, Substring,
     Overlay, CharLength, CurrentTimestamp)
 
-__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError',
-    'Cursor']
+__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
 
 
 class SQLiteExtract(Function):
@@ -152,6 +151,22 @@ def sign(value):
         return value
 
 
+def greatest(*args):
+    args = filter(lambda a: a is not None, args)
+    if args:
+        return max(args)
+    else:
+        return None
+
+
+def least(*args):
+    args = filter(lambda a: a is not None, args)
+    if args:
+        return min(args)
+    else:
+        return None
+
+
 MAPPING = {
     Extract: SQLiteExtract,
     Position: SQLitePosition,
@@ -162,35 +177,52 @@ MAPPING = {
     }
 
 
+class SQLiteCursor(sqlite.Cursor):
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        pass
+
+
+class SQLiteConnection(sqlite.Connection):
+
+    def cursor(self):
+        return super(SQLiteConnection, self).cursor(SQLiteCursor)
+
+
 class Database(DatabaseInterface):
 
     _local = threading.local()
     _conn = None
     flavor = Flavor(paramstyle='qmark', function_mapping=MAPPING)
+    IN_MAX = 200
 
-    def __new__(cls, database_name=':memory:'):
-        if (database_name == ':memory:'
+    def __new__(cls, name=':memory:'):
+        if (name == ':memory:'
                 and getattr(cls._local, 'memory_database', None)):
             return cls._local.memory_database
-        return DatabaseInterface.__new__(cls, database_name=database_name)
+        return DatabaseInterface.__new__(cls, name=name)
 
-    def __init__(self, database_name=':memory:'):
-        super(Database, self).__init__(database_name=database_name)
-        if database_name == ':memory:':
+    def __init__(self, name=':memory:'):
+        super(Database, self).__init__(name=name)
+        if name == ':memory:':
             Database._local.memory_database = self
 
     def connect(self):
-        if self.database_name == ':memory:':
+        if self.name == ':memory:':
             path = ':memory:'
         else:
-            db_filename = self.database_name + '.sqlite'
+            db_filename = self.name + '.sqlite'
             path = os.path.join(config.get('database', 'path'), db_filename)
             if not os.path.isfile(path):
                 raise IOError('Database "%s" doesn\'t exist!' % db_filename)
         if self._conn is not None:
             return self
         self._conn = sqlite.connect(path,
-            detect_types=sqlite.PARSE_DECLTYPES | sqlite.PARSE_COLNAMES)
+            detect_types=sqlite.PARSE_DECLTYPES | sqlite.PARSE_COLNAMES,
+            factory=SQLiteConnection)
         self._conn.create_function('extract', 2, SQLiteExtract.extract)
         self._conn.create_function('date_trunc', 2, date_trunc)
         self._conn.create_function('split_part', 3, split_part)
@@ -201,29 +233,32 @@ class Database(DatabaseInterface):
             self._conn.create_function('replace', 3, replace)
         self._conn.create_function('now', 0, now)
         self._conn.create_function('sign', 1, sign)
-        self._conn.create_function('greatest', -1, max)
-        self._conn.create_function('least', -1, min)
+        self._conn.create_function('greatest', -1, greatest)
+        self._conn.create_function('least', -1, least)
         self._conn.execute('PRAGMA foreign_keys = ON')
         return self
 
-    def cursor(self, autocommit=False, readonly=False):
+    def get_connection(self, autocommit=False, readonly=False):
         if self._conn is None:
             self.connect()
         if autocommit:
             self._conn.isolation_level = None
         else:
             self._conn.isolation_level = 'IMMEDIATE'
-        return Cursor(self._conn, self.database_name)
+        return self._conn
+
+    def put_connection(self, connection=None, close=False):
+        pass
 
     def close(self):
-        if self.database_name == ':memory:':
+        if self.name == ':memory:':
             return
         if self._conn is None:
             return
         self._conn = None
 
-    @staticmethod
-    def create(cursor, database_name):
+    @classmethod
+    def create(cls, connection, database_name):
         if database_name == ':memory:':
             path = ':memory:'
         else:
@@ -235,10 +270,9 @@ class Database(DatabaseInterface):
             cursor = conn.cursor()
             cursor.close()
 
-    @classmethod
-    def drop(cls, cursor, database_name):
+    def drop(self, connection, database_name):
         if database_name == ':memory:':
-            cls._local.memory_database._conn = None
+            self._local.memory_database._conn = None
             return
         if os.sep in database_name:
             return
@@ -270,8 +304,7 @@ class Database(DatabaseInterface):
         with open(path, 'wb') as file_p:
             file_p.write(data)
 
-    @staticmethod
-    def list(cursor):
+    def list(self):
         res = []
         listdir = [':memory:']
         try:
@@ -285,80 +318,48 @@ class Database(DatabaseInterface):
                 else:
                     db_name = db_file[:-7]
                 try:
-                    database = Database(db_name)
+                    database = Database(db_name).connect()
                 except Exception:
                     continue
-                cursor2 = database.cursor()
-                if cursor2.test():
+                if database.test():
                     res.append(db_name)
-                cursor2.close()
+                database.close()
         return res
 
-    @staticmethod
-    def init(cursor):
+    def init(self):
         from trytond.modules import get_module_info
-        sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
-        with open(sql_file) as fp:
-            for line in fp.read().split(';'):
-                if (len(line) > 0) and (not line.isspace()):
-                    cursor.execute(line)
-
-        ir_module = Table('ir_module')
-        ir_module_dependency = Table('ir_module_dependency')
-        for module in ('ir', 'res', 'webdav'):
-            state = 'uninstalled'
-            if module in ('ir', 'res'):
-                state = 'to install'
-            info = get_module_info(module)
-            insert = ir_module.insert(
-                [ir_module.create_uid, ir_module.create_date, ir_module.name,
-                    ir_module.state],
-                [[0, CurrentTimestamp(), module, state]])
-            cursor.execute(*insert)
-            cursor.execute('SELECT last_insert_rowid()')
-            module_id, = cursor.fetchone()
-            for dependency in info.get('depends', []):
-                insert = ir_module_dependency.insert(
-                    [ir_module_dependency.create_uid,
-                        ir_module_dependency.create_date,
-                        ir_module_dependency.module, ir_module_dependency.name
-                        ],
-                    [[0, CurrentTimestamp(), module_id, dependency]])
+        with self._conn as conn:
+            cursor = conn.cursor()
+            sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
+            with open(sql_file) as fp:
+                for line in fp.read().split(';'):
+                    if (len(line) > 0) and (not line.isspace()):
+                        cursor.execute(line)
+
+            ir_module = Table('ir_module')
+            ir_module_dependency = Table('ir_module_dependency')
+            for module in ('ir', 'res'):
+                state = 'uninstalled'
+                if module in ('ir', 'res'):
+                    state = 'to install'
+                info = get_module_info(module)
+                insert = ir_module.insert(
+                    [ir_module.create_uid, ir_module.create_date,
+                        ir_module.name, ir_module.state],
+                    [[0, CurrentTimestamp(), module, state]])
                 cursor.execute(*insert)
-
-
-class Cursor(CursorInterface):
-    IN_MAX = 200
-
-    def __init__(self, conn, database_name):
-        super(Cursor, self).__init__()
-        self._conn = conn
-        self.database_name = database_name
-        self.dbname = self.database_name  # XXX to remove
-        self.cursor = conn.cursor()
-
-    def __getattr__(self, name):
-        if _FIX_ROWCOUNT and name == 'rowcount':
-            return -1
-        return getattr(self.cursor, name)
-
-    def execute(self, sql, params=None):
-        if params:
-            return self.cursor.execute(sql, params)
-        else:
-            return self.cursor.execute(sql)
-
-    def close(self, close=False):
-        self.cursor.close()
-        self.rollback()
-
-    def commit(self):
-        super(Cursor, self).commit()
-        self._conn.commit()
-
-    def rollback(self):
-        super(Cursor, self).rollback()
-        self._conn.rollback()
+                cursor.execute('SELECT last_insert_rowid()')
+                module_id, = cursor.fetchone()
+                for dependency in info.get('depends', []):
+                    insert = ir_module_dependency.insert(
+                        [ir_module_dependency.create_uid,
+                            ir_module_dependency.create_date,
+                            ir_module_dependency.module,
+                            ir_module_dependency.name,
+                            ],
+                        [[0, CurrentTimestamp(), module_id, dependency]])
+                    cursor.execute(*insert)
+            conn.commit()
 
     def test(self):
         sqlite_master = Table('sqlite_master')
@@ -376,17 +377,19 @@ class Cursor(CursorInterface):
                 'ir_translation',
                 'ir_lang',
                 ])
-        try:
-            self.cursor.execute(*select)
-        except Exception:
-            return False
-        return len(self.cursor.fetchall()) != 0
+        with self._conn as conn:
+            cursor = conn.cursor()
+            try:
+                cursor.execute(*select)
+            except Exception:
+                return False
+            return len(cursor.fetchall()) != 0
 
-    def lastid(self):
-        self.cursor.execute('SELECT last_insert_rowid()')
-        return self.cursor.fetchone()[0]
+    def lastid(self, cursor):
+        # This call is not thread safe
+        return cursor.lastrowid
 
-    def lock(self, table):
+    def lock(self, connection, table):
         pass
 
     def has_constraint(self):
diff --git a/trytond/backend/sqlite/table.py b/trytond/backend/sqlite/table.py
index 236645e..1609ede 100644
--- a/trytond/backend/sqlite/table.py
+++ b/trytond/backend/sqlite/table.py
@@ -1,9 +1,11 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 
+from trytond.transaction import Transaction
 from trytond.backend.table import TableHandlerInterface
 import logging
 import re
+import warnings
 
 __all__ = ['TableHandler']
 
@@ -11,31 +13,32 @@ logger = logging.getLogger(__name__)
 
 
 class TableHandler(TableHandlerInterface):
-    def __init__(self, cursor, model, module_name=None, history=False):
-        super(TableHandler, self).__init__(cursor, model,
+    def __init__(self, model, module_name=None, history=False):
+        super(TableHandler, self).__init__(model,
                 module_name=module_name, history=history)
         self._columns = {}
         self._constraints = []
         self._fk_deltypes = {}
         self._indexes = []
-        self._field2module = {}
         self._model = model
 
+        cursor = Transaction().connection.cursor()
         # Create new table if necessary
-        if not self.table_exist(self.cursor, self.table_name):
+        if not self.table_exist(self.table_name):
             if not self.history:
-                self.cursor.execute('CREATE TABLE "%s" '
+                cursor.execute('CREATE TABLE "%s" '
                     '(id INTEGER PRIMARY KEY AUTOINCREMENT)'
                     % self.table_name)
             else:
-                self.cursor.execute('CREATE TABLE "%s" '
+                cursor.execute('CREATE TABLE "%s" '
                     '(__id INTEGER PRIMARY KEY AUTOINCREMENT, '
                     'id INTEGER)' % self.table_name)
 
         self._update_definitions()
 
     @staticmethod
-    def table_exist(cursor, table_name):
+    def table_exist(table_name):
+        cursor = Transaction().connection.cursor()
         cursor.execute("SELECT sql FROM sqlite_master "
             "WHERE type = 'table' AND name = ?",
             (table_name,))
@@ -68,38 +71,38 @@ class TableHandler(TableHandlerInterface):
         return True
 
     @staticmethod
-    def table_rename(cursor, old_name, new_name):
-        if (TableHandler.table_exist(cursor, old_name)
-                and not TableHandler.table_exist(cursor, new_name)):
+    def table_rename(old_name, new_name):
+        cursor = Transaction().connection.cursor()
+        if (TableHandler.table_exist(old_name)
+                and not TableHandler.table_exist(new_name)):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_name, new_name))
         # Rename history table
         old_history = old_name + "__history"
         new_history = new_name + "__history"
-        if (TableHandler.table_exist(cursor, old_history)
-                and not TableHandler.table_exist(cursor, new_history)):
+        if (TableHandler.table_exist(old_history)
+                and not TableHandler.table_exist(new_history)):
             cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
                 % (old_history, new_history))
 
     @staticmethod
-    def sequence_exist(cursor, sequence_name):
+    def sequence_exist(sequence_name):
         return True
 
     @staticmethod
-    def sequence_rename(cursor, old_name, new_name):
+    def sequence_rename(old_name, new_name):
         pass
 
     def column_exist(self, column_name):
         return column_name in self._columns
 
     def column_rename(self, old_name, new_name, exception=False):
+        cursor = Transaction().connection.cursor()
         if self.column_exist(old_name) and \
                 not self.column_exist(new_name):
             temp_table = '_temp_%s' % self.table_name
-            TableHandler.table_rename(self.cursor, self.table_name,
-                temp_table)
-            new_table = TableHandler(self.cursor, self._model,
-                history=self.history)
+            TableHandler.table_rename(self.table_name, temp_table)
+            new_table = TableHandler(self._model, history=self.history)
             for column, (notnull, hasdef, size, typname) \
                     in self._columns.iteritems():
                 if column == old_name:
@@ -109,12 +112,12 @@ class TableHandler(TableHandlerInterface):
             new_columns = new_table._columns.keys()
             old_columns = [x if x != old_name else new_name
                 for x in new_columns]
-            self.cursor.execute(('INSERT INTO "%s" (' +
+            cursor.execute(('INSERT INTO "%s" (' +
                     ','.join('"%s"' % x for x in new_columns) +
                     ') SELECT ' +
                     ','.join('"%s"' % x for x in old_columns) + ' ' +
                     'FROM "%s"') % (self.table_name, temp_table))
-            self.cursor.execute('DROP TABLE "%s"' % temp_table)
+            cursor.execute('DROP TABLE "%s"' % temp_table)
             self._update_definitions()
         elif exception and self.column_exist(new_name):
             raise Exception('Unable to rename column %s.%s to %s.%s: '
@@ -122,62 +125,56 @@ class TableHandler(TableHandlerInterface):
                 % (self.table_name, old_name, self.table_name, new_name,
                     self.table_name, new_name))
 
-    def _update_definitions(self):
-
+    def _update_definitions(self, columns=None, indexes=None):
+        if columns is None and indexes is None:
+            columns = indexes = True
+        cursor = Transaction().connection.cursor()
         # Fetch columns definitions from the table
-        self.cursor.execute('PRAGMA table_info("' + self.table_name + '")')
-        self._columns = {}
-        for _, column, type_, notnull, hasdef, _ in self.cursor.fetchall():
-            column = re.sub(r'^\"|\"$', '', column)
-            match = re.match(r'(\w+)(\((.*?)\))?', type_)
-            if match:
-                typname = match.group(1).upper()
-                size = match.group(3) and int(match.group(3)) or 0
-            else:
-                typname = type_.upper()
-                size = -1
-            self._columns[column] = {
-                'notnull': notnull,
-                'hasdef': hasdef,
-                'size': size,
-                'typname': typname,
-            }
+        if columns:
+            cursor.execute('PRAGMA table_info("' + self.table_name + '")')
+            self._columns = {}
+            for _, column, type_, notnull, hasdef, _ in cursor.fetchall():
+                column = re.sub(r'^\"|\"$', '', column)
+                match = re.match(r'(\w+)(\((.*?)\))?', type_)
+                if match:
+                    typname = match.group(1).upper()
+                    size = match.group(3) and int(match.group(3)) or 0
+                else:
+                    typname = type_.upper()
+                    size = -1
+                self._columns[column] = {
+                    'notnull': notnull,
+                    'hasdef': hasdef,
+                    'size': size,
+                    'typname': typname,
+                }
 
         # Fetch indexes defined for the table
-        try:
-            self.cursor.execute('PRAGMA index_list("' + self.table_name + '")')
-        except IndexError:  # There is sometimes IndexError
-            self.cursor.execute('PRAGMA index_list("' + self.table_name + '")')
-        self._indexes = [l[1] for l in self.cursor.fetchall()]
-
-        # Keep track of which module created each field
-        self._field2module = {}
-        if self.object_name is not None:
-            self.cursor.execute('SELECT f.name, f.module '
-                'FROM ir_model_field f '
-                'JOIN ir_model m on (f.model=m.id) '
-                'WHERE m.model = ?',
-                (self.object_name,))
-            for line in self.cursor.fetchall():
-                self._field2module[line[0]] = line[1]
+        if indexes:
+            try:
+                cursor.execute('PRAGMA index_list("' + self.table_name + '")')
+            except IndexError:  # There is sometimes IndexError
+                cursor.execute('PRAGMA index_list("' + self.table_name + '")')
+            self._indexes = [l[1] for l in cursor.fetchall()]
+
+    @property
+    def _field2module(self):
+        cursor = Transaction().connection.cursor()
+        cursor.execute('SELECT f.name, f.module '
+            'FROM ir_model_field f '
+            'JOIN ir_model m on (f.model=m.id) '
+            'WHERE m.model = ?',
+            (self.object_name,))
+        return dict(cursor)
 
     def alter_size(self, column_name, column_type):
-        logger.warning(
-            'Unable to alter size of column %s '
-            'of table %s!',
-            column_name, self.table_name)
+        warnings.warn('Unable to alter size of column with SQLite backend')
 
     def alter_type(self, column_name, column_type):
-        logger.warning(
-            'Unable to alter type of column %s '
-            'of table %s!',
-            column_name, self.table_name)
+        warnings.warn('Unable to alter type of column with SQLite backend')
 
     def db_default(self, column_name, value):
-        logger.warning(
-            'Unable to set default on column %s '
-            'of table %s!',
-            column_name, self.table_name)
+        warnings.warn('Unable to set default on column with SQLite backend')
 
     def add_raw_column(self, column_name, column_type, column_format,
             default_fun=None, field_size=None, migrate=True, string=''):
@@ -221,57 +218,55 @@ class TableHandler(TableHandlerInterface):
                         field_size)
             return
 
+        cursor = Transaction().connection.cursor()
         column_type = column_type[1]
         default = ''
-        self.cursor.execute(('ALTER TABLE "%s" ADD COLUMN "%s" %s' + default) %
+        cursor.execute(('ALTER TABLE "%s" ADD COLUMN "%s" %s' + default) %
                        (self.table_name, column_name, column_type))
 
         if column_format:
             # check if table is non-empty:
-            self.cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
-            if self.cursor.fetchone():
+            cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
+            if cursor.fetchone():
                 # Populate column with default values:
                 default = None
                 if default_fun is not None:
                     default = default_fun()
-                self.cursor.execute('UPDATE "' + self.table_name + '" '
+                cursor.execute('UPDATE "' + self.table_name + '" '
                     'SET "' + column_name + '" = ?',
                     (column_format(default),))
 
-        self._update_definitions()
+        self._update_definitions(columns=True)
 
     def add_fk(self, column_name, reference, on_delete=None):
-        logger.warning(
-            'Unable to add foreign key on table %s!',
-            self.table_name)
+        warnings.warn('Unable to add foreign key with SQLite backend')
 
     def drop_fk(self, column_name, table=None):
-        logger.warning(
-            'Unable to drop foreign key on table %s!',
-            self.table_name)
+        warnings.warn('Unable to drop foreign key with SQLite backend')
 
     def index_action(self, column_name, action='add', table=None):
         if isinstance(column_name, basestring):
             column_name = [column_name]
         index_name = self.table_name + "_" + '_'.join(column_name) + "_index"
 
+        cursor = Transaction().connection.cursor()
         if action == 'add':
             if index_name in self._indexes:
                 return
-            self.cursor.execute('CREATE INDEX "' + index_name + '" '
+            cursor.execute('CREATE INDEX "' + index_name + '" '
                 'ON "' + self.table_name + '" ( ' +
                 ','.join('"' + x + '"' for x in column_name) +
                 ')')
-            self._update_definitions()
+            self._update_definitions(indexes=True)
         elif action == 'remove':
             if len(column_name) == 1:
-                if self._field2module.get(column_name[0], self.module_name) \
-                        != self.module_name:
+                if self._field2module.get(column_name[0],
+                        self.module_name) != self.module_name:
                     return
 
             if index_name in self._indexes:
-                self.cursor.execute('DROP INDEX "%s" ' % (index_name,))
-                self._update_definitions()
+                cursor.execute('DROP INDEX "%s" ' % (index_name,))
+                self._update_definitions(indexes=True)
         else:
             raise Exception('Index action not supported!')
 
@@ -280,35 +275,24 @@ class TableHandler(TableHandlerInterface):
             return
 
         if action == 'add':
-            logger.warning(
-                'Unable to set not null on column %s '
-                'of table %s!',
-                column_name, self.table_name)
+            warnings.warn('Unable to set not null with SQLite backend')
         elif action == 'remove':
-            logger.warning(
-                'Unable to remove not null on column %s '
-                'of table %s!',
-                column_name, self.table_name)
+            warnings.warn('Unable to remove not null with SQLite backend')
         else:
             raise Exception('Not null action not supported!')
 
     def add_constraint(self, ident, constraint, exception=False):
-        logger.warning(
-            'Unable to add constraint on table %s!',
-            self.table_name)
+        warnings.warn('Unable to add constraint with SQLite backend')
 
     def drop_constraint(self, ident, exception=False, table=None):
-        logger.warning(
-            'Unable to drop constraint on table %s!',
-            self.table_name)
+        warnings.warn('Unable to drop constraint with SQLite backend')
 
     def drop_column(self, column_name, exception=False):
-        logger.warning(
-            'Unable to drop "%s" column on table %s!',
-            column_name, self.table_name)
+        warnings.warn('Unable to drop column with SQLite backend')
 
     @staticmethod
-    def drop_table(cursor, model, table, cascade=False):
+    def drop_table(model, table, cascade=False):
+        cursor = Transaction().connection.cursor()
         cursor.execute('DELETE from ir_model_data where '
             'model = \'%s\'' % model)
 
diff --git a/trytond/backend/table.py b/trytond/backend/table.py
index afdeb6b..887d415 100644
--- a/trytond/backend/table.py
+++ b/trytond/backend/table.py
@@ -7,15 +7,13 @@ class TableHandlerInterface(object):
     Define generic interface to handle database table
     '''
 
-    def __init__(self, cursor, model, module_name=None, history=False):
+    def __init__(self, model, module_name=None, history=False):
         '''
-        :param cursor: the database cursor
         :param model: the Model linked to the table
         :param module_name: the module name
         :param history: a boolean to define if it is a history table
         '''
         super(TableHandlerInterface, self).__init__()
-        self.cursor = cursor
         if history:
             self.table_name = model._table + '__history'
         else:
@@ -29,44 +27,40 @@ class TableHandlerInterface(object):
         self.history = history
 
     @staticmethod
-    def table_exist(cursor, table_name):
+    def table_exist(table_name):
         '''
         Table exist
 
-        :param cursor: the database cursor
         :param table_name: the table name
         :return: a boolean
         '''
         raise NotImplementedError
 
     @staticmethod
-    def table_rename(cursor, old_name, new_name):
+    def table_rename(old_name, new_name):
         '''
         Rename table
 
-        :param cursor: the database cursor
         :param old_name: the old table name
         :param new_name: the new table name
         '''
         raise NotImplementedError
 
     @staticmethod
-    def sequence_exist(cursor, sequence_name):
+    def sequence_exist(sequence_name):
         '''
         Sequence exist
 
-        :param cursor: the database cursor
         :param sequence_name: the sequence name
         :return: a boolean
         '''
         raise NotImplementedError
 
     @staticmethod
-    def sequence_rename(cursor, old_name, new_name):
+    def sequence_rename(old_name, new_name):
         '''
         Rename sequence
 
-        :param cursor: the database cursor
         :param old_name: the old sequence name
         :param new_name: the new sequence name
         '''
@@ -206,7 +200,7 @@ class TableHandlerInterface(object):
         raise NotImplementedError
 
     @staticmethod
-    def drop_table(cursor, model, table, cascade=False):
+    def drop_table(model, table, cascade=False):
         '''
         Remove a table and clean ir_model_data from the given model.
 
diff --git a/trytond/cache.py b/trytond/cache.py
index a239987..4a89382 100644
--- a/trytond/cache.py
+++ b/trytond/cache.py
@@ -43,11 +43,10 @@ class Cache(object):
         return key
 
     def get(self, key, default=None):
-        cursor = Transaction().cursor
+        dbname = Transaction().database.name
         key = self._key(key)
         with self._lock:
-            cache = self._cache.setdefault(cursor.dbname,
-                LRUDict(self.size_limit))
+            cache = self._cache.setdefault(dbname, LRUDict(self.size_limit))
             try:
                 result = cache[key] = cache.pop(key)
                 return result
@@ -55,11 +54,10 @@ class Cache(object):
                 return default
 
     def set(self, key, value):
-        cursor = Transaction().cursor
+        dbname = Transaction().database.name
         key = self._key(key)
         with self._lock:
-            cache = self._cache.setdefault(cursor.dbname,
-                LRUDict(self.size_limit))
+            cache = self._cache.setdefault(dbname, LRUDict(self.size_limit))
             try:
                 cache[key] = value
             except TypeError:
@@ -67,15 +65,15 @@ class Cache(object):
         return value
 
     def clear(self):
-        cursor = Transaction().cursor
-        Cache.reset(cursor.dbname, self._name)
+        dbname = Transaction().database.name
+        Cache.reset(dbname, self._name)
         with self._lock:
-            self._cache[cursor.dbname] = LRUDict(self.size_limit)
+            self._cache[dbname] = LRUDict(self.size_limit)
 
     @staticmethod
     def clean(dbname):
-        with Transaction().new_cursor():
-            cursor = Transaction().cursor
+        with Transaction().new_transaction() as transaction,\
+                transaction.connection.cursor() as cursor:
             table = Table('ir_cache')
             cursor.execute(*table.select(table.timestamp, table.name))
             timestamps = {}
@@ -97,25 +95,24 @@ class Cache(object):
 
     @staticmethod
     def resets(dbname):
-        with Transaction().new_cursor():
-            cursor = Transaction().cursor
-            table = Table('ir_cache')
-            with Cache._resets_lock:
-                Cache._resets.setdefault(dbname, set())
-                for name in Cache._resets[dbname]:
-                    cursor.execute(*table.select(table.name,
+        table = Table('ir_cache')
+        with Transaction().new_transaction() as transaction,\
+                transaction.connection.cursor() as cursor,\
+                Cache._resets_lock:
+            Cache._resets.setdefault(dbname, set())
+            for name in Cache._resets[dbname]:
+                cursor.execute(*table.select(table.name,
+                        where=table.name == name))
+                if cursor.fetchone():
+                    # It would be better to insert only
+                    cursor.execute(*table.update([table.timestamp],
+                            [CurrentTimestamp()],
                             where=table.name == name))
-                    if cursor.fetchone():
-                        # It would be better to insert only
-                        cursor.execute(*table.update([table.timestamp],
-                                [CurrentTimestamp()],
-                                where=table.name == name))
-                    else:
-                        cursor.execute(*table.insert(
-                                [table.timestamp, table.name],
-                                [[CurrentTimestamp(), name]]))
-                Cache._resets[dbname].clear()
-            cursor.commit()
+                else:
+                    cursor.execute(*table.insert(
+                            [table.timestamp, table.name],
+                            [[CurrentTimestamp(), name]]))
+            Cache._resets[dbname].clear()
 
     @classmethod
     def drop(cls, dbname):
@@ -128,6 +125,8 @@ class LRUDict(OrderedDict):
     Dictionary with a size limit.
     If size limit is reached, it will remove the first added items.
     """
+    __slots__ = ('size_limit',)
+
     def __init__(self, size_limit, *args, **kwargs):
         assert size_limit > 0
         self.size_limit = size_limit
@@ -150,3 +149,24 @@ class LRUDict(OrderedDict):
     def _check_size_limit(self):
         while len(self) > self.size_limit:
             self.popitem(last=False)
+
+
+class LRUDictTransaction(LRUDict):
+    """
+    Dictionary with a size limit. (see LRUDict)
+    It is refreshed when transaction counter is changed.
+    """
+    __slots__ = ('transaction', 'counter')
+
+    def __init__(self, *args, **kwargs):
+        super(LRUDictTransaction, self).__init__(*args, **kwargs)
+        self.transaction = Transaction()
+        self.counter = self.transaction.counter
+
+    def clear(self):
+        super(LRUDictTransaction, self).clear()
+        self.counter = self.transaction.counter
+
+    def refresh(self):
+        if self.counter != self.transaction.counter:
+            self.clear()
diff --git a/bin/trytond b/trytond/commandline.py
old mode 100755
new mode 100644
similarity index 54%
copy from bin/trytond
copy to trytond/commandline.py
index 89d7b31..45bb900
--- a/bin/trytond
+++ b/trytond/commandline.py
@@ -1,47 +1,52 @@
-#!/usr/bin/env python
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
-import sys
-import os
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 import argparse
-
-DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
-    '..', '..', 'trytond')))
-if os.path.isdir(DIR):
-    sys.path.insert(0, os.path.dirname(DIR))
+import os
+import logging
+import logging.config
+import logging.handlers
+from contextlib import contextmanager
 
 from trytond import __version__
-from trytond import server
 
+logger = logging.getLogger(__name__)
 
-def parse_commandline():
-    options = {}
 
-    parser = argparse.ArgumentParser(prog='trytond')
+def get_parser():
+    parser = argparse.ArgumentParser()
 
     parser.add_argument('--version', action='version',
         version='%(prog)s ' + __version__)
     parser.add_argument("-c", "--config", dest="configfile", metavar='FILE',
         default=os.environ.get('TRYTOND_CONFIG'), help="specify config file")
-    parser.add_argument('--dev', dest='dev', action='store_true',
-        help='enable development mode')
     parser.add_argument("-v", "--verbose", action="store_true",
         dest="verbose", help="enable verbose mode")
+    parser.add_argument('--dev', dest='dev', action='store_true',
+        help='enable development mode')
 
     parser.add_argument("-d", "--database", dest="database_names", nargs='+',
         default=[], metavar='DATABASE', help="specify the database name")
+    parser.add_argument("--logconf", dest="logconf", metavar='FILE',
+        help="logging configuration file (ConfigParser format)")
+
+    return parser
+
+
+def get_parser_daemon():
+    parser = get_parser()
+    parser.add_argument("--pidfile", dest="pidfile", metavar='FILE',
+        help="file where the server pid will be stored")
+    return parser
+
+
+def get_parser_admin():
+    parser = get_parser()
+
     parser.add_argument("-u", "--update", dest="update", nargs='+', default=[],
         metavar='MODULE', help="update a module")
     parser.add_argument("--all", dest="update", action="append_const",
         const="ir", help="update all installed modules")
 
-    parser.add_argument("--pidfile", dest="pidfile", metavar='FILE',
-        help="file where the server pid will be stored")
-    parser.add_argument("--logconf", dest="logconf", metavar='FILE',
-        help="logging configuration file (ConfigParser format)")
-    parser.add_argument("--cron", dest="cron", action="store_true",
-        help="enable cron")
-
     parser.epilog = ('The first time a database is initialized admin '
         'password is read from file defined by TRYTONPASSFILE '
         'environment variable or interactively ask user.\n'
@@ -49,32 +54,35 @@ def parse_commandline():
         'environment variable.\n'
         'The database URI can be specified in the TRYTOND_DATABASE_URI '
         'environment variable.')
+    return parser
+
+
+def config_log(options):
+    if options.logconf:
+        logging.config.fileConfig(options.logconf)
+        logging.getLogger('server').info('using %s as logging '
+            'configuration file', options.logconf)
+    else:
+        logformat = ('%(process)s %(thread)s [%(asctime)s] '
+            '%(levelname)s %(name)s %(message)s')
+        if options.verbose:
+            if options.dev:
+                level = logging.DEBUG
+            else:
+                level = logging.INFO
+        else:
+            level = logging.ERROR
+        logging.basicConfig(level=level, format=logformat)
+    logging.captureWarnings(True)
+
 
-    options = parser.parse_args()
-
-    if not options.database_names and options.update:
-        parser.error('Missing database option')
-    return options
-
-
-if '--profile' in sys.argv:
-    import profile
-    import pstats
-    import tempfile
-    sys.argv.remove('--profile')
-
-    options = parse_commandline()
-    statfile = tempfile.mkstemp(".stat", "trytond-")[1]
-    profile.run('server.TrytonServer(options).run()', statfile)
-    s = pstats.Stats(statfile)
-    s.sort_stats('cumulative').print_stats()
-    s.sort_stats('call').print_stats()
-    s.sort_stats('time').print_stats()
-    s.sort_stats('time')
-    s.print_callers()
-    s.print_callees()
-
-    os.remove(statfile)
-else:
-    options = parse_commandline()
-    server.TrytonServer(options).run()
+ at contextmanager
+def pidfile(options):
+    path = options.pidfile
+    if not path:
+        yield
+    else:
+        with open(path, 'w') as fd:
+            fd.write('%d' % os.getpid())
+        yield
+        os.unlink(path)
diff --git a/trytond/config.py b/trytond/config.py
index 46f5d1f..44ceaf9 100644
--- a/trytond/config.py
+++ b/trytond/config.py
@@ -3,9 +3,11 @@
 import os
 import ConfigParser
 import urlparse
+import logging
 
 __all__ = ['config', 'get_hostname', 'get_port', 'split_netloc',
     'parse_listen', 'parse_uri']
+logger = logging.getLogger(__name__)
 
 
 def get_hostname(netloc):
@@ -39,11 +41,9 @@ class TrytonConfigParser(ConfigParser.RawConfigParser):
 
     def __init__(self):
         ConfigParser.RawConfigParser.__init__(self)
-        self.add_section('jsonrpc')
-        self.set('jsonrpc', 'listen', 'localhost:8000')
-        self.set('jsonrpc', 'data', '/var/www/localhost/tryton')
-        self.add_section('xmlrpc')
-        self.add_section('webdav')
+        self.add_section('web')
+        self.set('web', 'listen', 'localhost:8000')
+        self.set('web', 'root', '/var/www/localhost/tryton')
         self.add_section('database')
         self.set('database', 'uri',
             os.environ.get('TRYTOND_DATABASE_URI', 'sqlite://'))
@@ -63,10 +63,12 @@ class TrytonConfigParser(ConfigParser.RawConfigParser):
         self.add_section('report')
         self.set('report', 'unoconv',
             'pipe,name=trytond;urp;StarOffice.ComponentContext')
+        self.update_etc()
 
     def update_etc(self, configfile=os.environ.get('TRYTOND_CONFIG')):
         if not configfile:
             return
+        logger.info('using %s as configuration file', configfile)
         self.read(configfile)
 
     def get(self, section, option, *args, **kwargs):
diff --git a/trytond/const.py b/trytond/const.py
index 23503c0..07a56ec 100644
--- a/trytond/const.py
+++ b/trytond/const.py
@@ -1,8 +1,12 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 OPERATORS = (
+    'where',
+    'not where',
     'child_of',
     'not child_of',
+    'parent_of',
+    'not parent_of',
     '=',
     '!=',
     'like',
diff --git a/trytond/convert.py b/trytond/convert.py
index c3000dc..d8f2758 100644
--- a/trytond/convert.py
+++ b/trytond/convert.py
@@ -43,7 +43,7 @@ class MenuitemTagHandler:
         self.xml_id = None
 
     def startElement(self, name, attributes):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         values = {}
 
@@ -354,7 +354,7 @@ class Fs2bdAccessor:
         models = Model.browse(ids)
         for model in models:
             if model.id in self.browserecord[module][model_name]:
-                for cache in Transaction().cursor.cache.values():
+                for cache in Transaction().cache.values():
                     for cache in (cache, cache.get('_language_cache',
                                 {}).values()):
                         if (model_name in cache
@@ -460,8 +460,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
 
             if name in self.taghandlerlist:
                 self.taghandler = self.taghandlerlist[name]
-                self.taghandler.startElement(name, attributes)
-
             elif name == "data":
                 self.noupdate = bool(int(attributes.get("noupdate", '0')))
                 self.grouped = bool(int(attributes.get('grouped', 0)))
@@ -482,7 +480,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
             else:
                 logger.info("Tag %s not supported", (name,))
                 return
-        elif not self.skip_data:
+        if self.taghandler and not self.skip_data:
             self.taghandler.startElement(name, attributes)
 
     def characters(self, data):
@@ -604,7 +602,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
                 old_values = self.ModelData.load_values(old_values)
 
             for key in old_values:
-                if isinstance(old_values[key], str):
+                if isinstance(old_values[key], bytes):
                     # Fix for migration to unicode
                     old_values[key] = old_values[key].decode('utf-8')
 
@@ -644,7 +642,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
 
                 # if the fs value is the same has in the db, whe ignore it
                 val = values[key]
-                if isinstance(values[key], str):
+                if isinstance(values[key], bytes):
                     # Fix for migration to unicode
                     val = values[key].decode('utf-8')
                 if db_field == val:
@@ -783,7 +781,7 @@ def post_import(pool, module, to_delete):
     """
     Remove the records that are given in to_delete.
     """
-    cursor = Transaction().cursor
+    transaction = Transaction()
     mdata_delete = []
     ModelData = pool.get("ir.model.data")
 
@@ -810,9 +808,9 @@ def post_import(pool, module, to_delete):
                 logger.warning(
                     'Could not delete id %d of model %s because model no '
                     'longer exists.', db_id, model)
-            cursor.commit()
+            transaction.commit()
         except Exception:
-            cursor.rollback()
+            transaction.rollback()
             logger.error(
                 'Could not delete id: %d of model %s\n'
                 'There should be some relation '
@@ -826,7 +824,7 @@ def post_import(pool, module, to_delete):
                             'active': False,
                             })
                 except Exception:
-                    cursor.rollback()
+                    transaction.rollback()
                     logger.error(
                         'Could not inactivate id: %d of model %s\n',
                         db_id, model, exc_info=True)
@@ -834,6 +832,6 @@ def post_import(pool, module, to_delete):
     # Clean model_data:
     if mdata_delete:
         ModelData.delete(mdata_delete)
-        cursor.commit()
+        transaction.commit()
 
     return True
diff --git a/trytond/cron.py b/trytond/cron.py
new file mode 100644
index 0000000..f327b04
--- /dev/null
+++ b/trytond/cron.py
@@ -0,0 +1,43 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import threading
+import logging
+
+from trytond.pool import Pool
+from trytond.transaction import Transaction
+
+__all__ = ['run']
+logger = logging.getLogger(__name__)
+
+
+def run(options):
+    database_list = Pool.database_list()
+    for dbname in options.database_names:
+        thread = _threads.get(dbname)
+        if thread and thread.is_alive():
+            logger.info('skip "%s" as previous cron still running', dbname)
+            continue
+        pool = Pool(dbname)
+        if dbname not in database_list:
+            with Transaction().start(dbname, 0, readonly=True):
+                pool.init()
+        if not pool.lock.acquire(0):
+            logger.warning('can not acquire lock on "%s"', dbname)
+            continue
+        try:
+            try:
+                Cron = pool.get('ir.cron')
+            except KeyError:
+                logger.error(
+                    'missing "ir.cron" on "%s"', dbname, exc_info=True)
+                continue
+        finally:
+            pool.lock.release()
+        thread = threading.Thread(
+                target=Cron.run,
+                args=(dbname,), kwargs={})
+        logger.info('start thread for "%s"', dbname)
+        thread.start()
+        _threads[dbname] = thread
+_threads = {}
+Pool.start()
diff --git a/trytond/exceptions.py b/trytond/exceptions.py
index dd086b1..1b05f78 100644
--- a/trytond/exceptions.py
+++ b/trytond/exceptions.py
@@ -2,7 +2,11 @@
 # this repository contains the full copyright notices and license terms.
 
 
-class UserError(Exception):
+class TrytonException(Exception):
+    pass
+
+
+class UserError(TrytonException):
 
     def __init__(self, message, description=''):
         super(UserError, self).__init__('UserError', (message, description))
@@ -11,7 +15,7 @@ class UserError(Exception):
         self.code = 1
 
 
-class UserWarning(Exception):
+class UserWarning(TrytonException):
 
     def __init__(self, name, message, description=''):
         super(UserWarning, self).__init__('UserWarning', (name, message,
@@ -22,14 +26,7 @@ class UserWarning(Exception):
         self.code = 2
 
 
-class NotLogged(Exception):
-
-    def __init__(self):
-        super(NotLogged, self).__init__('NotLogged')
-        self.code = 3
-
-
-class ConcurrencyException(Exception):
+class ConcurrencyException(TrytonException):
 
     def __init__(self, message):
         super(ConcurrencyException, self).__init__('ConcurrencyException',
diff --git a/trytond/ir/__init__.py b/trytond/ir/__init__.py
index ab1e31e..a000482 100644
--- a/trytond/ir/__init__.py
+++ b/trytond/ir/__init__.py
@@ -11,6 +11,7 @@ from .property import *
 from .action import *
 from .model import *
 from .attachment import *
+from .note import *
 from .cron import *
 from .lang import *
 from .export import *
@@ -61,6 +62,8 @@ def register():
         ModelData,
         PrintModelGraphStart,
         Attachment,
+        Note,
+        NoteRead,
         Cron,
         Lang,
         Export,
@@ -95,4 +98,5 @@ def register():
         module='ir', type_='wizard')
     Pool.register(
         ModelGraph,
+        ModelWorkflowGraph,
         module='ir', type_='report')
diff --git a/trytond/ir/action.py b/trytond/ir/action.py
index 5ff7e7f..40970b0 100644
--- a/trytond/ir/action.py
+++ b/trytond/ir/action.py
@@ -102,7 +102,6 @@ class ActionKeyword(ModelSQL, ModelView):
     __name__ = 'ir.action.keyword'
     keyword = fields.Selection([
             ('tree_open', 'Open tree'),
-            ('tree_action', 'Action tree'),
             ('form_print', 'Print form'),
             ('form_action', 'Action form'),
             ('form_relate', 'Form relate'),
@@ -129,7 +128,7 @@ class ActionKeyword(ModelSQL, ModelView):
         TableHandler = backend.get('TableHandler')
         super(ActionKeyword, cls).__register__(module_name)
 
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.index_action(['keyword', 'model'], 'add')
 
     def get_groups(self, name):
@@ -311,9 +310,12 @@ class ActionMixin(ModelSQL):
             for field in later:
                 del values[field]
             action_values['type'] = cls.default_type()
-            cursor = Transaction().cursor
-            if cursor.nextid(cls._table):
-                cursor.setnextid(cls._table, cursor.currid(Action._table))
+            transaction = Transaction()
+            database = transaction.database
+            cursor = transaction.connection.cursor()
+            if database.nextid(transaction.connection, cls._table):
+                database.setnextid(transaction.connection, cls._table,
+                    database.currid(transaction.connection, Action._table))
             if 'action' not in values:
                 action, = Action.create([action_values])
                 values['action'] = action.id
@@ -323,7 +325,8 @@ class ActionMixin(ModelSQL):
             cursor.execute(*ir_action.update(
                     [ir_action.id], [action.id],
                     where=ir_action.id == record.id))
-            cursor.update_auto_increment(cls._table, action.id)
+            transaction.database.update_auto_increment(
+                transaction.connection, cls._table, action.id)
             record = cls(action.id)
             new_records.append(record)
             cls.write([record], later)
@@ -397,6 +400,10 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
             ('odp', 'OpenDocument Presentation'),
             ('ods', 'OpenDocument Spreadsheet'),
             ('odg', 'OpenDocument Graphics'),
+            ('plain', 'Plain Text'),
+            ('xml', 'XML'),
+            ('html', 'HTML'),
+            ('xhtml', 'XHTML'),
             ], string='Template Extension', required=True,
         translate=False)
     extension = fields.Selection([
@@ -481,8 +488,9 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
         TableHandler = backend.get('TableHandler')
         super(ActionReport, cls).__register__(module_name)
 
-        cursor = Transaction().cursor
-        table = TableHandler(cursor, cls, module_name)
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
+        table = TableHandler(cls, module_name)
         action_report = cls.__table__()
 
         # Migration from 1.0 report_name_uniq has been removed
@@ -503,7 +511,7 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
             cls.write(cls.browse(ids), {'extension': 'odt'})
 
             table.drop_column("output_format")
-            TableHandler.dropTable(cursor, 'ir.action.report.outputformat',
+            TableHandler.dropTable('ir.action.report.outputformat',
                 'ir_action_report_outputformat')
 
         # Migrate from 2.0 remove required on extension
@@ -517,7 +525,7 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
         # report_content_custom to remove base64 encoding
         if (table.column_exist('report_content_data')
                 and table.column_exist('report_content_custom')):
-            limit = cursor.IN_MAX
+            limit = transaction.database.IN_MAX
             cursor.execute(*action_report.select(
                     Count(action_report.id)))
             report_count, = cursor.fetchone()
@@ -590,8 +598,8 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
         contents = {}
         converter = fields.Binary.cast
         default = None
-        format_ = Transaction().context.pop('%s.%s'
-            % (cls.__name__, name), '')
+        format_ = Transaction().context.get(
+            '%s.%s' % (cls.__name__, name), '')
         if format_ == 'size':
             converter = len
             default = 0
@@ -667,6 +675,7 @@ class ActionActWindow(ActionMixin, ModelSQL, ModelView):
     context = fields.Char('Context Value')
     order = fields.Char('Order Value')
     res_model = fields.Char('Model')
+    context_model = fields.Char('Context Model')
     act_window_views = fields.One2Many('ir.action.act_window.view',
             'act_window', 'Views')
     views = fields.Function(fields.Binary('Views'), 'get_views')
@@ -705,12 +714,12 @@ class ActionActWindow(ActionMixin, ModelSQL, ModelView):
 
     @classmethod
     def __register__(cls, module_name):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         TableHandler = backend.get('TableHandler')
         act_window = cls.__table__()
         super(ActionActWindow, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.0: new search_value format
         cursor.execute(*act_window.update(
@@ -903,7 +912,7 @@ class ActionActWindowView(ModelSQL, ModelView):
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
         super(ActionActWindowView, cls).__register__(module_name)
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 1.0 remove multi
         table.drop_column('multi')
diff --git a/trytond/ir/attachment.py b/trytond/ir/attachment.py
index 28bdf1d..dcf4f59 100644
--- a/trytond/ir/attachment.py
+++ b/trytond/ir/attachment.py
@@ -3,14 +3,13 @@
 import os
 import hashlib
 from sql.operators import Concat
-from sql.conditionals import Coalesce
 
 from ..model import ModelView, ModelSQL, fields, Unique
 from ..config import config
 from .. import backend
 from ..transaction import Transaction
 from ..pyson import Eval
-from ..pool import Pool
+from .resource import ResourceMixin
 
 __all__ = [
     'Attachment',
@@ -24,7 +23,7 @@ def firstline(description):
         return ''
 
 
-class Attachment(ModelSQL, ModelView):
+class Attachment(ResourceMixin, ModelSQL, ModelView):
     "Attachment"
     __name__ = 'ir.attachment'
     name = fields.Char('Name', required=True)
@@ -37,8 +36,6 @@ class Attachment(ModelSQL, ModelView):
                 }, depends=['type']), 'get_data', setter='set_data')
     description = fields.Text('Description')
     summary = fields.Function(fields.Char('Summary'), 'on_change_with_summary')
-    resource = fields.Reference('Resource', selection='models_get',
-        select=True)
     link = fields.Char('Link', states={
             'invisible': Eval('type') != 'link',
             }, depends=['type'])
@@ -47,31 +44,25 @@ class Attachment(ModelSQL, ModelView):
     data_size = fields.Function(fields.Integer('Data size', states={
                 'invisible': Eval('type') != 'data',
                 }, depends=['type']), 'get_data')
-    last_modification = fields.Function(fields.DateTime('Last Modification'),
-        'get_last_modification')
-    last_user = fields.Function(fields.Char('Last User'),
-        'get_last_user')
 
     @classmethod
     def __setup__(cls):
         super(Attachment, cls).__setup__()
-        cls._order.insert(0, ('last_modification', 'DESC'))
-
         table = cls.__table__()
         cls._sql_constraints += [
             ('resource_name',
                 Unique(table, table.resource, table.name),
-                'The  names of attachments must be unique by resource!'),
+                'The names of attachments must be unique by resource.'),
         ]
 
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         super(Attachment, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         attachment = cls.__table__()
 
         # Migration from 1.4 res_model and res_id merged into resource
@@ -91,30 +82,13 @@ class Attachment(ModelSQL, ModelView):
         return 'data'
 
     @staticmethod
-    def default_resource():
-        return Transaction().context.get('resource')
-
-    @staticmethod
     def default_collision():
         return 0
 
-    @staticmethod
-    def models_get():
-        pool = Pool()
-        Model = pool.get('ir.model')
-        ModelAccess = pool.get('ir.model.access')
-        models = Model.search([])
-        access = ModelAccess.get_access([m.model for m in models])
-        res = []
-        for model in models:
-            if access[model.model]['read']:
-                res.append([model.model, model.name])
-        return res
-
     def get_data(self, name):
-        db_name = Transaction().cursor.dbname
-        format_ = Transaction().context.pop('%s.%s'
-            % (self.__name__, name), '')
+        db_name = Transaction().database.name
+        format_ = Transaction().context.get(
+            '%s.%s' % (self.__name__, name), '')
         value = None
         if name == 'data_size' or format_ == 'size':
             value = 0
@@ -142,9 +116,10 @@ class Attachment(ModelSQL, ModelView):
     def set_data(cls, attachments, name, value):
         if value is None:
             return
-        cursor = Transaction().cursor
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         table = cls.__table__()
-        db_name = cursor.dbname
+        db_name = transaction.database.name
         directory = os.path.join(config.get('database', 'path'), db_name)
         if not os.path.isdir(directory):
             os.makedirs(directory, 0770)
@@ -191,72 +166,3 @@ class Attachment(ModelSQL, ModelView):
     @fields.depends('description')
     def on_change_with_summary(self, name=None):
         return firstline(self.description or '')
-
-    def get_last_modification(self, name):
-        return (self.write_date if self.write_date else self.create_date
-            ).replace(microsecond=0)
-
-    @staticmethod
-    def order_last_modification(tables):
-        table, _ = tables[None]
-        return [Coalesce(table.write_date, table.create_date)]
-
-    def get_last_user(self, name):
-        return (self.write_uid.rec_name if self.write_uid
-            else self.create_uid.rec_name)
-
-    @classmethod
-    def check_access(cls, ids, mode='read'):
-        pool = Pool()
-        ModelAccess = pool.get('ir.model.access')
-        if ((Transaction().user == 0)
-                or not Transaction().context.get('_check_access')):
-            return
-        model_names = set()
-        with Transaction().set_context(_check_access=False):
-            for attachment in cls.browse(ids):
-                if attachment.resource:
-                    model_names.add(attachment.resource.__name__)
-        for model_name in model_names:
-            ModelAccess.check(model_name, mode=mode)
-
-    @classmethod
-    def read(cls, ids, fields_names=None):
-        cls.check_access(ids, mode='read')
-        return super(Attachment, cls).read(ids, fields_names=fields_names)
-
-    @classmethod
-    def delete(cls, attachments):
-        cls.check_access([a.id for a in attachments], mode='delete')
-        super(Attachment, cls).delete(attachments)
-
-    @classmethod
-    def write(cls, attachments, values, *args):
-        all_attachments = []
-        actions = iter((attachments, values) + args)
-        for records, _ in zip(actions, actions):
-            all_attachments += records
-        cls.check_access([a.id for a in all_attachments], mode='write')
-        super(Attachment, cls).write(attachments, values, *args)
-        cls.check_access(all_attachments, mode='write')
-
-    @classmethod
-    def create(cls, vlist):
-        attachments = super(Attachment, cls).create(vlist)
-        cls.check_access([a.id for a in attachments], mode='create')
-        return attachments
-
-    @classmethod
-    def view_header_get(cls, value, view_type='form'):
-        pool = Pool()
-        Model = pool.get('ir.model')
-        value = super(Attachment, cls).view_header_get(value,
-                view_type=view_type)
-        resource = Transaction().context.get('resource')
-        if resource:
-            model_name, record_id = resource.split(',', 1)
-            ir_model, = Model.search([('model', '=', model_name)])
-            Resource = pool.get(model_name)
-            record = Resource(int(record_id))
-            value = '%s - %s - %s' % (ir_model.name, record.rec_name, value)
-        return value
diff --git a/trytond/ir/cron.py b/trytond/ir/cron.py
index 470e901..9e384fc 100644
--- a/trytond/ir/cron.py
+++ b/trytond/ir/cron.py
@@ -9,13 +9,13 @@ from email.mime.text import MIMEText
 from email.header import Header
 from ast import literal_eval
 
-from ..model import ModelView, ModelSQL, fields
-from ..tools import get_smtp_server
+from ..model import ModelView, ModelSQL, fields, dualmethod
 from ..transaction import Transaction
 from ..pool import Pool
 from .. import backend
 from ..config import config
 from ..cache import Cache
+from ..sendmail import sendmail
 
 __all__ = [
     'Cron',
@@ -70,15 +70,20 @@ class Cron(ModelSQL, ModelView):
                 'request_body': ("The following action failed to execute "
                     "properly: \"%s\"\n%s\n Traceback: \n\n%s\n")
                 })
+        cls._buttons.update({
+                'run_once': {
+                    'icon': 'tryton-executable',
+                    },
+                })
 
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         cron = cls.__table__()
 
         # Migration from 2.0: rename numbercall, doall and nextcall
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('numbercall', 'number_calls')
         table.column_rename('doall', 'repeat_missed')
         table.column_rename('nextcall', 'next_call')
@@ -126,59 +131,56 @@ class Cron(ModelSQL, ModelView):
         '''
         return _INTERVALTYPES[cron.interval_type](cron.interval_number)
 
-    @classmethod
-    def send_error_message(cls, cron):
-        tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
-        tb_s = tb_s.decode('utf-8', 'ignore')
-        subject = cls.raise_user_error('request_title',
-            raise_exception=False)
-        body = cls.raise_user_error('request_body',
-            (cron.name, cron.__url__, tb_s),
-            raise_exception=False)
-
-        from_addr = config.get('email', 'from')
-        to_addr = cron.request_user.email
-
-        msg = MIMEText(body, _charset='utf-8')
-        msg['To'] = to_addr
-        msg['From'] = from_addr
-        msg['Subject'] = Header(subject, 'utf-8')
-        if not to_addr:
-            logger.error(msg.as_string())
-        else:
-            try:
-                server = get_smtp_server()
-                server.sendmail(from_addr, to_addr, msg.as_string())
-                server.quit()
-            except Exception:
-                logger.error('Unable to deliver email:\n %s',
-                    msg.as_string(), exc_info=True)
-
-    @classmethod
-    def _callback(cls, cron):
+    def send_error_message(self):
         pool = Pool()
         Config = pool.get('ir.configuration')
-        try:
-            args = (cron.args or []) and literal_eval(cron.args)
+
+        if self.request_user.language:
+            language = self.request_user.language.code
+        else:
+            language = Config.get_language()
+
+        with Transaction().set_user(self.user.id), \
+                Transaction().set_context(language=language):
+            tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
+            tb_s = tb_s.decode('utf-8', 'ignore')
+            subject = self.raise_user_error('request_title',
+                raise_exception=False)
+            body = self.raise_user_error('request_body',
+                (self.name, self.__url__, tb_s),
+                raise_exception=False)
+
+            from_addr = config.get('email', 'from')
+            to_addr = self.request_user.email
+
+            msg = MIMEText(body, _charset='utf-8')
+            msg['To'] = to_addr
+            msg['From'] = from_addr
+            msg['Subject'] = Header(subject, 'utf-8')
+            if not to_addr:
+                logger.error(msg.as_string())
+            else:
+                sendmail(from_addr, to_addr, msg)
+
+    @dualmethod
+    @ModelView.button
+    def run_once(cls, crons):
+        pool = Pool()
+        for cron in crons:
+            if cron.args:
+                args = literal_eval(cron.args)
+            else:
+                args = []
             Model = pool.get(cron.model)
             with Transaction().set_user(cron.user.id):
                 getattr(Model, cron.function)(*args)
-        except Exception:
-            Transaction().cursor.rollback()
-
-            req_user = cron.request_user
-            language = (req_user.language.code if req_user.language
-                    else Config.get_language())
-            with Transaction().set_user(cron.user.id), \
-                    Transaction().set_context(language=language):
-                cls.send_error_message(cron)
 
     @classmethod
     def run(cls, db_name):
         now = datetime.datetime.now()
         with Transaction().start(db_name, 0) as transaction:
             Cache.clean(db_name)
-            transaction.cursor.lock(cls._table)
+            transaction.database.lock(transaction.connection, cls._table)
             crons = cls.search([
                     ('number_calls', '!=', 0),
                     ('next_call', '<=', datetime.datetime.now()),
@@ -191,7 +193,11 @@ class Cron(ModelSQL, ModelView):
                     first = True
                     while next_call < now and number_calls != 0:
                         if first or cron.repeat_missed:
-                            cls._callback(cron)
+                            try:
+                                cron.run_once()
+                            except Exception:
+                                transaction.rollback()
+                                cron.send_error_message()
                         next_call += cls.get_delta(cron)
                         if number_calls > 0:
                             number_calls -= 1
@@ -202,8 +208,8 @@ class Cron(ModelSQL, ModelView):
                     if not number_calls:
                         cron.active = False
                     cron.save()
-                    transaction.cursor.commit()
+                    transaction.commit()
                 except Exception:
-                    transaction.cursor.rollback()
+                    transaction.rollback()
                     logger.error('Running cron %s', cron.id, exc_info=True)
             Cache.resets(db_name)
diff --git a/trytond/ir/lang.py b/trytond/ir/lang.py
index a6f8c24..f429ffe 100644
--- a/trytond/ir/lang.py
+++ b/trytond/ir/lang.py
@@ -1,7 +1,13 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+from __future__ import absolute_import
+
+import sys
 import datetime
 import warnings
+warnings.filterwarnings('ignore', "", ImportWarning)
+from locale import CHAR_MAX
+warnings.resetwarnings()
 from ast import literal_eval
 
 from ..model import ModelView, ModelSQL, fields, Check
@@ -10,13 +16,8 @@ from ..tools import datetime_strftime
 from ..transaction import Transaction
 from ..pool import Pool
 from .time_locale import TIME_LOCALE
-from ..backend.database import CursorInterface
 
-warnings.filterwarnings('ignore', "", ImportWarning)
-from locale import CHAR_MAX
-warnings.resetwarnings()
-
-CursorInterface.cache_keys.add('translate_name')
+Transaction.cache_keys.add('translate_name')
 
 __all__ = [
     'Lang',
@@ -154,9 +155,11 @@ class Lang(ModelSQL, ModelView):
         Check the date format
         '''
         for lang in langs:
+            date = lang.date
+            if sys.version_info < (3,):
+                date = date.encode('utf-8')
             try:
-                datetime_strftime(datetime.datetime.now(),
-                        lang.date.encode('utf-8'))
+                datetime_strftime(datetime.datetime.now(), date)
             except Exception:
                 cls.raise_user_error('invalid_date', {
                         'format': lang.date,
@@ -415,7 +418,10 @@ class Lang(ModelSQL, ModelView):
                         TIME_LOCALE[code][f][datetime.timetuple()[i]])
             format = format.replace('%p',
                 TIME_LOCALE[code]['%p'][datetime.timetuple()[3] < 12 and 0
-                    or 1]).encode('utf-8')
-        else:
-            format = format.encode('utf-8')
-        return datetime_strftime(datetime, format).decode('utf-8')
+                    or 1])
+        if sys.version_info < (3,):
+            format.encode('utf-8')
+        result = datetime_strftime(datetime, format)
+        if sys.version_info < (3,):
+            result = result.decode('utf-8')
+        return result
diff --git a/trytond/ir/lang.xml b/trytond/ir/lang.xml
index 9729ff9..f14fb61 100644
--- a/trytond/ir/lang.xml
+++ b/trytond/ir/lang.xml
@@ -104,6 +104,14 @@ this repository contains the full copyright notices and license terms. -->
             <field name="decimal_point">,</field>
             <field name="thousands_sep">.</field>
         </record>
+        <record model="ir.lang" id="lang_lo">
+            <field name="code">lo_LA</field>
+            <field name="name">ລາວ</field>
+            <field name="date">%d/%m/%Y</field>
+            <field name="grouping">[3, 3, 0]</field>
+            <field name="decimal_point">.</field>
+            <field name="thousands_sep">,</field>
+        </record>
         <record model="ir.lang" id="lang_lt">
             <field name="code">lt_LT</field>
             <field name="name">Lithuanian</field>
@@ -144,6 +152,14 @@ this repository contains the full copyright notices and license terms. -->
             <field name="decimal_point">,</field>
             <field name="thousands_sep">.</field>
         </record>
+        <record model="ir.lang" id="lang_zh_CN">
+            <field name="code">zh_CN</field>
+            <field name="name">中国(简体)</field>
+            <field name="date">%Y-%m-%d</field>
+            <field name="grouping">[3, 0]</field>
+            <field name="decimal_point">.</field>
+            <field name="thousands_sep">,</field>
+        </record>
 
         <record model="ir.ui.view" id="lang_view_tree">
             <field name="model">ir.lang</field>
diff --git a/trytond/ir/locale/bg_BG.po b/trytond/ir/locale/bg_BG.po
index d73bda2..11dd4f9 100644
--- a/trytond/ir/locale/bg_BG.po
+++ b/trytond/ir/locale/bg_BG.po
@@ -2,11 +2,14 @@
 msgid ""
 msgstr "Content-Type: text/plain; charset=utf-8\n"
 
+#, fuzzy
 msgctxt "error:access_error:"
 msgid ""
 "You try to bypass an access rule.\n"
 "(Document type: %s)"
 msgstr ""
+"Опитвате се да прескочите право за достъп!\n"
+"(Вид документ: %s)"
 
 msgctxt "error:delete_xml_record:"
 msgid "You are not allowed to delete this record."
@@ -58,8 +61,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "Имената на прикачените файлове трябва да са уникални по ресурс!"
 
 msgctxt "error:ir.cron:"
@@ -145,23 +149,24 @@ msgstr "Модела трябва да е уникален!"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "Зависимостта трябва да е уникална за модул!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Липсващи зависимости %s за модул \"%s\""
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
 msgstr ""
+"От модула който исакте да деинсталирате зависят следните инсталирани модули:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "Името на модула трябва да е уникално!"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "Не може да изтривате модул който инсталиран или ще бъде инсталиран"
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -239,11 +244,14 @@ msgctxt "error:ir.ui.view:"
 msgid "Invalid XML for view \"%s\"."
 msgstr ""
 
+#, fuzzy
 msgctxt "error:read_error:"
 msgid ""
 "You try to read records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"Опитвате се да прочетете запис който вече не съществува!\n"
+"(Вид документ: %s)"
 
 msgctxt "error:recursion_error:"
 msgid ""
@@ -293,11 +301,14 @@ msgctxt "error:too_many_relations_found:"
 msgid "Too many relations found: %r in %s"
 msgstr "Намерени са твърде много зависимости: %r в %s"
 
+#, fuzzy
 msgctxt "error:write_error:"
 msgid ""
 "You try to write on records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"Опитвате се да прочетете запис който вече не съществува!\n"
+"(Вид документ: %s)"
 
 msgctxt "error:write_xml_record:"
 msgid "You are not allowed to modify this record."
@@ -363,9 +374,10 @@ msgctxt "field:ir.action,write_uid:"
 msgid "Write User"
 msgstr "Променено от"
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,act_window_domains:"
 msgid "Domains"
-msgstr ""
+msgstr "Домейн"
 
 msgctxt "field:ir.action.act_window,act_window_views:"
 msgid "Views"
@@ -384,6 +396,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Стойност на котекст"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Създадено на"
@@ -396,9 +412,10 @@ msgctxt "field:ir.action.act_window,domain:"
 msgid "Domain Value"
 msgstr "Стойност на домейн"
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,domains:"
 msgid "Domains"
-msgstr ""
+msgstr "Домейн"
 
 #, fuzzy
 msgctxt "field:ir.action.act_window,groups:"
@@ -999,9 +1016,10 @@ msgctxt "field:ir.configuration,id:"
 msgid "ID"
 msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.configuration,language:"
 msgid "language"
-msgstr ""
+msgstr "Език"
 
 #, fuzzy
 msgctxt "field:ir.configuration,rec_name:"
@@ -1538,152 +1556,249 @@ msgstr "Ниво"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Деца"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Създадено на"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Създадено от"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Зависимости"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Име"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Родители"
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Име"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Състояние"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Версия"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Променено на"
 
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Променено от"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Действие"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Създадено на"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Създадено от"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Име"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Последователност"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Състояние"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Променено на"
 
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Променено от"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Процент"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Създадено на"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Създадено от"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Модул"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Име"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Име"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Състояние"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Променено на"
 
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Променено от"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Модули за обновяване"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Създадено на"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Създадено от"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Последна промяна"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Последен потребител"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Име"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Ресурс"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Променено на"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Променено от"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Създадено на"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Създадено от"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Име"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Потребител"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Променено на"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Променено от"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Създадено на"
@@ -2327,9 +2442,10 @@ msgctxt "field:ir.ui.menu,action:"
 msgid "Action"
 msgstr "Действие"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu,action_keywords:"
 msgid "Action Keywords"
-msgstr ""
+msgstr "Бърз клавиш на действие"
 
 msgctxt "field:ir.ui.menu,active:"
 msgid "Active"
@@ -2751,11 +2867,14 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "Правилото е удовлетворено ако поне един тест е успешен"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Python израз изчислен със запис представен със \"self\"\n"
+"Извиква действието ако е истина."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2872,6 +2991,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Започване на изчакващите инталации/обновявания"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Свойства"
@@ -2948,13 +3071,18 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Графика"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Действие на активния прозорец"
 
+#, fuzzy
 msgctxt "model:ir.action.act_window.domain,name:"
 msgid "Action act window domain"
-msgstr ""
+msgstr "Изглед на действие на активния на прозорец"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_model_data_form_domain_all"
@@ -3063,9 +3191,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Френски"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Български"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3121,34 +3250,43 @@ msgstr "Печат на графика на модел"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Модул"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Помощник за настройка на модук - други"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Първи помощник на конфигуриране на модул"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Задаване на помощника да се стартира след инсталиране на модула"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Помощник за настройка на модук - други"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Зависимости на модула"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Приключи инсталиране/обновяване на модул"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Начало на инсталиране/обновяване на модул"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3203,13 +3341,15 @@ msgctxt "model:ir.translation.export.start,name:"
 msgid "Export translation"
 msgstr "Извличане на превод - файл"
 
+#, fuzzy
 msgctxt "model:ir.translation.set.start,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "Изчистване на преводи"
 
+#, fuzzy
 msgctxt "model:ir.translation.set.succeed,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "Изчистване на преводи"
 
 msgctxt "model:ir.translation.update.start,name:"
 msgid "Update translation"
@@ -3332,6 +3472,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Модули"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Свойства"
@@ -3372,9 +3516,10 @@ msgctxt "model:ir.ui.menu,name:menu_translation_form"
 msgid "Translations"
 msgstr "Преводи"
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_translation_set"
 msgid "Set Translations"
-msgstr ""
+msgstr "Изчистване на преводи"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_update"
 msgid "Synchronize Translations"
@@ -3416,17 +3561,19 @@ msgctxt "model:ir.ui.view,name:"
 msgid "View"
 msgstr "Изглед"
 
+#, fuzzy
 msgctxt "model:ir.ui.view.show.start,name:"
 msgid "Show view"
-msgstr ""
+msgstr "Показване на изглед"
 
 msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Ширина на дърво с изгледи"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
@@ -3494,55 +3641,55 @@ msgstr "Отдясно наляво"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Инсталиран"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Не е инсталиран"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "За инсталиране"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "За премахване"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "За обновяване"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Приключен"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Отваряне"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Инсталиран"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Не е инсталиран"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "За инсталиране"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "За премахване"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "За обновяване"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Неизвестен"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3584,9 +3731,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Модел"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Справка"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3650,9 +3798,10 @@ msgctxt "view:ir.action.act_window.domain:"
 msgid "Domain"
 msgstr "Домейн"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domains"
-msgstr ""
+msgstr "Домейн"
 
 #, fuzzy
 msgctxt "view:ir.action.act_window.view:"
@@ -3723,15 +3872,20 @@ msgctxt "view:ir.attachment:"
 msgid "Attachments"
 msgstr "Прикачени файлове"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Последна промяна"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr "Действие за стартиране"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Планирано действие"
 
@@ -3771,9 +3925,10 @@ msgctxt "view:ir.model.button:"
 msgid "Buttons"
 msgstr "Бутони"
 
+#, fuzzy
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "Модел на данни"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
@@ -3800,9 +3955,10 @@ msgctxt "view:ir.model:"
 msgid "Model Description"
 msgstr "Описание на модел"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Конфицурация на модул"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
@@ -3810,37 +3966,39 @@ msgstr ""
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "Добре дошли в помощника за конфигуриране на модула!"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
 msgstr ""
+"Може да настроите инсталацията си в зависимост от инсталираните модули."
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Елементи на помощника за конфигуриране"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
-msgstr ""
+msgstr "Следваща стъпа на помощника за конфигуриране!"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Зависимости"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Зависимост"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
-msgstr ""
+msgstr "Обновяване на системата завършено"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
-msgstr ""
+msgstr "Модулите са обновени / инсталирани !"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
@@ -3848,44 +4006,66 @@ msgstr ""
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "System Upgrade"
-msgstr ""
+msgstr "Обновяване на системата"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Your system will be upgraded."
-msgstr ""
+msgstr "Системата ще бъде обновена."
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "Отказ от инсталалиране"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "Отказ от деинсталиране"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "Отказ от обновяване"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "Отбелязване за инсталиране"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "Отбелязване за деинсталиране (beta)"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "Отбелязване за обновяване"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Модул"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Модули"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Дата"
+
+msgctxt "view:ir.note:"
+msgid "Note"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Потребител"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Свойства"
@@ -3979,21 +4159,24 @@ msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
 msgstr "Извличане на превод"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Изчистване на преводи"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
-msgstr ""
+msgstr "Синхронизиране на преводите"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Изчистване на преводи"
 
 msgctxt "view:ir.translation.update.start:"
 msgid "Synchronize Translations"
@@ -4031,9 +4214,10 @@ msgctxt "view:ir.ui.menu:"
 msgid "Menu"
 msgstr "Меню"
 
+#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr ""
+msgstr "Показване"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
@@ -4047,13 +4231,15 @@ msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Ширина на дърво с изгледи"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "Ширина на дърво с изгледи"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
@@ -4071,37 +4257,40 @@ msgctxt "wizard_button:ir.model.print_model_graph,start,print_:"
 msgid "Print"
 msgstr "Печат"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "Добре"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "Добре"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отказ"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Напред"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отказ"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "Добре"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отказ"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Започване на обновяване"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/ca_ES.po b/trytond/ir/locale/ca_ES.po
index 08ae998..97f96f3 100644
--- a/trytond/ir/locale/ca_ES.po
+++ b/trytond/ir/locale/ca_ES.po
@@ -71,8 +71,9 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definició del correu electrònic sobre l'informe \"%s\", no és correcta."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "El nom dels adjunts ha de ser únic per recurs."
 
 msgctxt "error:ir.cron:"
@@ -417,6 +418,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Context"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Data creació"
@@ -1669,6 +1674,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Mòduls a actualitzar"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Data creació"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Usuari creació"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última modificació"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Últim usuari"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nom"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurs"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Data modificació"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Usuari modificació"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Data creació"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Usuari creació"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nom"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuari"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Data modificació"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Usuari modificació"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Data creació"
@@ -2827,6 +2928,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realitza instal·lacions/actualitzacions pendents"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propietats"
@@ -2903,6 +3008,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gràfica"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Accions de finestra"
@@ -3105,6 +3214,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Inici instal·lació/actualització mòdul"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Propietat"
@@ -3285,6 +3402,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Mòduls"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propietats"
@@ -3537,9 +3658,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Model"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Informe"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3682,6 +3804,10 @@ msgid "Action to trigger"
 msgstr "Acció de disparador"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Acció planificada"
 
@@ -3837,6 +3963,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Mòduls"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Data"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuari"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propietats"
diff --git a/trytond/ir/locale/cs_CZ.po b/trytond/ir/locale/cs_CZ.po
index d71a1fa..d5b3532 100644
--- a/trytond/ir/locale/cs_CZ.po
+++ b/trytond/ir/locale/cs_CZ.po
@@ -59,7 +59,7 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 
 msgctxt "error:ir.cron:"
@@ -383,6 +383,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr ""
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -1635,6 +1639,86 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr ""
 
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr ""
+
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr ""
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr ""
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr ""
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -2777,6 +2861,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr ""
@@ -2853,6 +2941,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr ""
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr ""
@@ -3055,6 +3147,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr ""
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr ""
@@ -3235,6 +3335,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr ""
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr ""
@@ -3488,7 +3592,7 @@ msgid "Model"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
+msgid "Report"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
@@ -3632,6 +3736,10 @@ msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr ""
 
@@ -3785,6 +3893,26 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr ""
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr ""
diff --git a/trytond/ir/locale/de_DE.po b/trytond/ir/locale/de_DE.po
index ac65d63..e3eeac9 100644
--- a/trytond/ir/locale/de_DE.po
+++ b/trytond/ir/locale/de_DE.po
@@ -4,14 +4,6 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
 
 msgctxt "error:access_error:"
 msgid ""
-"You try to bypass an access rule!\n"
-"(Document type: %s)"
-msgstr ""
-"Fehlende Zugriffsberechtigung.\n"
-"(Dokumententyp: %s)"
-
-msgctxt "error:access_error:"
-msgid ""
 "You try to bypass an access rule.\n"
 "(Document type: %s)"
 msgstr ""
@@ -78,8 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Ungültige E-Mailadresse in Bericht \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 "Der Name für einen Anhang kann nur einmal pro Ressource vergeben werden!"
 
@@ -281,14 +274,6 @@ msgstr "Ungültige XML-Daten für Sicht \"%s\"."
 
 msgctxt "error:read_error:"
 msgid ""
-"You try to read records that don't exist anymore!\n"
-"(Document type: %s)"
-msgstr ""
-"Leseversuch von nicht mehr vorhandenen Datensätzen.\n"
-"(Dokumententyp: %s)"
-
-msgctxt "error:read_error:"
-msgid ""
 "You try to read records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
@@ -351,14 +336,6 @@ msgstr "Zu viele Beziehungen gefunden: %r in %s"
 
 msgctxt "error:write_error:"
 msgid ""
-"You try to write on records that don't exist anymore!\n"
-"(Document type: %s)"
-msgstr ""
-"Schreibversuch auf nicht mehr vorhandene Datensätze.\n"
-"(Dokumententyp: %s)"
-
-msgctxt "error:write_error:"
-msgid ""
 "You try to write on records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
@@ -449,6 +426,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Kontext"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Erstellungsdatum"
@@ -1701,6 +1682,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Zu aktualisierende Module"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Erstellungsdatum"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Erstellt durch"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Letzte Änderung"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Letzter Benutzer"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Name"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Ressource"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Zuletzt geändert"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Letzte Änderung durch"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Erstellungsdatum"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Erstellt durch"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Name"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Benutzer"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Zuletzt geändert"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Letzte Änderung durch"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Erstellungsdatum"
@@ -2862,6 +2939,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Vorgemerkte Installationen / Aktualisierungen durchführen"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Eigenschaften"
@@ -2938,6 +3019,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Diagramm"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Aktion aktives Fenster"
@@ -3140,6 +3225,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Modulinstallation Aktualisierung Start"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Eigenschaft"
@@ -3320,6 +3413,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Module"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Eigenschaften"
@@ -3572,9 +3669,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modell"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Bericht"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3717,6 +3815,10 @@ msgid "Action to trigger"
 msgstr "Auszuführende Aktion"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Geplante Aktion"
 
@@ -3870,6 +3972,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Module"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Datum"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Benutzer"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Eigenschaften"
@@ -3899,14 +4023,6 @@ msgctxt "view:ir.rule:"
 msgid "Test"
 msgstr "Test"
 
-msgctxt "view:ir.sequence.strict:"
-msgid "Legend (for prefix, suffix)"
-msgstr "Legende (für Präfix, Suffix)"
-
-msgctxt "view:ir.sequence.strict:"
-msgid "Sequences Strict"
-msgstr "Strikte Nummernkreise"
-
 msgctxt "view:ir.sequence.type:"
 msgid "Sequence Type"
 msgstr "Nummernkreistyp"
diff --git a/trytond/ir/locale/es_AR.po b/trytond/ir/locale/es_AR.po
index a3ebf6e..a123811 100644
--- a/trytond/ir/locale/es_AR.po
+++ b/trytond/ir/locale/es_AR.po
@@ -70,8 +70,9 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definición de correo electrónico en el informe «%s» no es correcta."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
 
 msgctxt "error:ir.cron:"
@@ -422,6 +423,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor del contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -1674,6 +1679,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última Modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último Usuario"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -2834,6 +2935,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar instalaciones/actualizaciones pendientes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -2910,6 +3015,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gráfico"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Ventana de acciones"
@@ -3112,6 +3221,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Iniciar la instalación o actualizaciones de módulos"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Propiedad"
@@ -3292,6 +3409,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3544,9 +3665,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Informe"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3689,6 +3811,10 @@ msgid "Action to trigger"
 msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Acción programada"
 
@@ -3844,6 +3970,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Fecha"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuario"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propiedades"
diff --git a/trytond/ir/locale/es_CO.po b/trytond/ir/locale/es_CO.po
index f9154cc..c6e6b48 100644
--- a/trytond/ir/locale/es_CO.po
+++ b/trytond/ir/locale/es_CO.po
@@ -70,8 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "El correo electronico definido en el informe \"%s\" es inválido."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
 
 msgctxt "error:ir.cron:"
@@ -162,23 +163,25 @@ msgstr "¡El modelo debe ser único!"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "¡Las dependencias por módulo deben ser únicas!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Faltan las dependencias %s para el módulo \"%s\""
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
 msgstr ""
+"Los módulos que está intentando desinstalar dependen de módulos instalados:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "¡El nombre del módulo debe ser único!"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
 msgstr ""
+"No puede eliminar un módulo que está instalado o que va a ser instalado"
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -248,11 +251,14 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"Al Tiempo\" y otros son mutuamente excluyentes!"
 
+#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
+"Condición \"%(condition)s\" no es una expressión python válida en el "
+"disparador \"%s(trigger)s\"."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -416,6 +422,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor del Contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Fecha de Creación"
@@ -1522,152 +1532,248 @@ msgstr "Nivel"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Hijos"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha de Creación"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creado por Usuario"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dependencias"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Padres"
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Versión"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha de Modificación"
 
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Modificado por Usuario"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Acción"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha de Creación"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creado por Usuario"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Secuencia"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha de Modificación"
 
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Modificado por Usuario"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Porcentaje"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha de Creación"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creado por Usuario"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha de Modificación"
 
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Modificado por Usuario"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Módulos a actualizar"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Fecha de Creación"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Creado por Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última Modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último Usuario"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Fecha de Modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Modificado por Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Fecha de Creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Creado por Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Fecha de Modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Modificado por Usuario"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Fecha de Creación"
@@ -2704,11 +2810,14 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "La regla se satisface si al menos una condición es cierta"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Una instrucción Python evaluada con el registro representado por \"self\"\n"
+"Se dispara la acción si es verdadera."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2826,6 +2935,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar Instalaciones/Actualizaciones Pendientes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -2902,6 +3015,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gráfico"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Acción ventana acción"
@@ -3016,9 +3133,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Francés"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Búlgaro"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3074,34 +3192,43 @@ msgstr "Imprimir Gráfico del Modelo"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Configuración del Módulo Terminada"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Primer Asistente de Configuración de Módulo"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
 msgstr ""
+"Asistente de configuración a ejecutar después de la instalaciń del módulo"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Siguiente Asistente de Configuración de Módulo"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Dependencias del módulo"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Actualización del Módulo Terminada"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Inicio de Asistente de Instalación del Módulo"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3284,6 +3411,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3446,55 +3577,55 @@ msgstr "Derecha-a-Izquierda"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Instalado"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "No instalado"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Pendiente de ser instalado"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Pendiente de ser eliminado"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Pendiente de ser actualizado"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Terminado"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Abrir"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Instalado"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "No instalado"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Pendiente de ser instalado"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Pendiente de ser eliminado"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Pendiente de ser actualizado"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Desconocido"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3536,9 +3667,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Reporte"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3672,15 +3804,20 @@ msgctxt "view:ir.attachment:"
 msgid "Attachments"
 msgstr "Adjuntos"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Última Modificación"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Acción Programada"
 
@@ -3750,90 +3887,115 @@ msgstr "Descripción del modelo"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Configuración del módulo"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
-msgstr ""
+msgstr "La configuracion ha terminado."
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "Bienvenido al asistente de configuración del módulo!"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
 msgstr ""
+"Usted será capaz de configurar la instalación en función de los módulos que "
+"ha instalado."
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Asistentes de Configuración"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
-msgstr ""
+msgstr "¡Siguiente Paso del Asistente de Configuración!"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dependencias"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Dependencia"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
-msgstr ""
+msgstr "Actualización del Sistema Finalizada"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
-msgstr ""
+msgstr "Los módulos se han actualizado / instalado"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
-msgstr ""
+msgstr "Esta operación puede demorar varios minutos."
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "System Upgrade"
-msgstr ""
+msgstr "Actualización del Sistema"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Your system will be upgraded."
-msgstr ""
+msgstr "Su sistema sera actualizado."
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "Cancelar Instalación"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "Cancelar Desinstalación"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "Cancelar Actualización"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "Marcar para Instalar"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "Marcar para Desinstalar (beta)"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "Marcar para Actualizar"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Módulos"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Fecha"
+
+msgctxt "view:ir.note:"
+msgid "Note"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuario"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3981,9 +4143,10 @@ msgctxt "view:ir.ui.menu:"
 msgid "Menu"
 msgstr "Menú"
 
+#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr ""
+msgstr "_Mostrar"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
@@ -4023,35 +4186,35 @@ msgstr "Imprimir"
 
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Siguiente"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Iniciar Mejora"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/es_EC.po b/trytond/ir/locale/es_EC.po
index adcc03e..58c50ed 100644
--- a/trytond/ir/locale/es_EC.po
+++ b/trytond/ir/locale/es_EC.po
@@ -70,8 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "La definición de correo electrónico sobre el informe \"%s\" no es válida."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "¡Los nombres de los archivos adjuntos deben ser únicos por recurso!"
 
 msgctxt "error:ir.cron:"
@@ -116,19 +117,19 @@ msgstr "¡el punto decimal y el separador de miles deben ser distintos!"
 
 msgctxt "error:ir.model.access:"
 msgid "You can not create this kind of document! (%s)"
-msgstr "¡No puede crear este tipo de documento! (%s)"
+msgstr "No puede crear este tipo de documento (%s)."
 
 msgctxt "error:ir.model.access:"
 msgid "You can not delete this document! (%s)"
-msgstr "¡No puede eliminar este documento! (%s)"
+msgstr "No puede eliminar este documento (%s)."
 
 msgctxt "error:ir.model.access:"
 msgid "You can not read this document! (%s)"
-msgstr "¡No puede leer este documento! (%s)"
+msgstr "No puede leer este documento (%s)."
 
 msgctxt "error:ir.model.access:"
 msgid "You can not write in this document! (%s)"
-msgstr "¡No puede escribir en este documento! (%s)"
+msgstr "No puede escribir en este documento (%s)."
 
 msgctxt "error:ir.model.button:"
 msgid "The button name in model must be unique!"
@@ -420,6 +421,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor del contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Fecha de creación"
@@ -662,7 +667,7 @@ msgstr "Impresión directa"
 
 msgctxt "field:ir.action.report,email:"
 msgid "Email"
-msgstr "Correo electrónico"
+msgstr "Email"
 
 msgctxt "field:ir.action.report,extension:"
 msgid "Extension"
@@ -698,7 +703,7 @@ msgstr "Nombre"
 
 msgctxt "field:ir.action.report,pyson_email:"
 msgid "PySON Email"
-msgstr "Correo electrónico PySON"
+msgstr "Email PySON"
 
 msgctxt "field:ir.action.report,rec_name:"
 msgid "Name"
@@ -822,7 +827,7 @@ msgstr "Creado por usuario"
 
 msgctxt "field:ir.action.wizard,email:"
 msgid "Email"
-msgstr "Correo electrónico"
+msgstr "Email"
 
 msgctxt "field:ir.action.wizard,groups:"
 msgid "Groups"
@@ -1672,6 +1677,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Fecha de creación"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Creado por usuario"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último usuario"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Fecha de modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Modificado por usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Fecha de creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Creado por usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Fecha de modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Modificado por usuario"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Fecha de creación"
@@ -2694,7 +2795,7 @@ msgstr ""
 
 msgctxt "help:ir.rule.group,default_p:"
 msgid "Add this rule to all users by default"
-msgstr "Añadir esta regla a todos los usuarios por defecto"
+msgstr "Agregar esta regla a todos los usuarios por defecto"
 
 msgctxt "help:ir.rule.group,global_p:"
 msgid ""
@@ -2832,6 +2933,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar instalaciones/actualizaciones pendientes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -2908,6 +3013,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gráfico"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Acción de ventana"
@@ -3110,6 +3219,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Iniciar la instalación o actualización de módulos"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Propiedad"
@@ -3290,6 +3407,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3542,9 +3663,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Informe"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3687,6 +3809,10 @@ msgid "Action to trigger"
 msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Acción programada"
 
@@ -3842,6 +3968,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Fecha"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuario"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propiedades"
diff --git a/trytond/ir/locale/es_ES.po b/trytond/ir/locale/es_ES.po
index 76cd62d..b07e341 100644
--- a/trytond/ir/locale/es_ES.po
+++ b/trytond/ir/locale/es_ES.po
@@ -71,8 +71,9 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definición de correo electrónico sobre el informe \"%s\" no es correcta."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "El nombre de los adjuntos debe ser único por registro."
 
 msgctxt "error:ir.cron:"
@@ -419,6 +420,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor del contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -1671,6 +1676,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a actualizar"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último usuario"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -2831,6 +2932,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar instalaciones/actualizaciones pendientes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -2907,6 +3012,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gráfico"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Acción de ventana"
@@ -3109,6 +3218,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Iniciar la instalación o actualización de módulos"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Propiedades"
@@ -3289,6 +3406,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3541,9 +3662,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Informe"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3686,6 +3808,10 @@ msgid "Action to trigger"
 msgstr "Acción a disparar"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Acción planificada"
 
@@ -3840,6 +3966,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Fecha"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuario"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propiedades"
diff --git a/trytond/ir/locale/es_MX.po b/trytond/ir/locale/es_MX.po
index 88da459..de9e9b0 100644
--- a/trytond/ir/locale/es_MX.po
+++ b/trytond/ir/locale/es_MX.po
@@ -71,8 +71,9 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 "La definición de correo electrónico sobre el informe \"%s\" no es correcta."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "El nombre de los adjuntos debe ser único por registro."
 
 msgctxt "error:ir.cron:"
@@ -161,25 +162,32 @@ msgctxt "error:ir.model:"
 msgid "The model must be unique!"
 msgstr "El modelo debe ser único."
 
+#, fuzzy
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "Las dependencias deben ser únicas por módulo."
 
+#, fuzzy
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Faltan las dependencias %s para el módulo \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
 msgstr ""
+"Los módulos que está intentando desinstalar depende de otros módulos "
+"instalados:"
 
+#, fuzzy
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "El nombre del módulo debe ser único."
 
+#, fuzzy
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "No puede eliminar un módulo que está instalado o será instalado."
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -245,11 +253,14 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"Por tiempo\" y otros son mutuamente excluyentes."
 
+#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
+"La condición \"%(condition)s\" no es una expresión Python válida en el "
+"disparador \"P%(trigger)s\"."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -415,6 +426,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor del contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -1519,154 +1534,287 @@ msgctxt "field:ir.model.print_model_graph.start,level:"
 msgid "Level"
 msgstr "Nivel"
 
+#, fuzzy
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Hijos"
 
+#, fuzzy
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha creación"
 
+#, fuzzy
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Usuario creación"
 
+#, fuzzy
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dependencias"
 
+#, fuzzy
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
+#, fuzzy
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Padres"
 
+#, fuzzy
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
+#, fuzzy
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
+#, fuzzy
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Versión"
 
+#, fuzzy
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha modificación"
 
+#, fuzzy
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Usuario modificación"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Acción"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha creación"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Usuario creación"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Secuencia"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha modificación"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Usuario modificación"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Porcentaje"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Fecha creación"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Usuario creación"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nombre"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Estado"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Fecha modificación"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Usuario modificación"
 
+#, fuzzy
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Módulos a actualizar"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último usuario"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Fecha creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Usuario creación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nombre"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Fecha modificación"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Usuario modificación"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Fecha creación"
@@ -2703,11 +2851,14 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "La regla es correcta si al menos una condición es cierta."
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Una instrucción de Python evaluada con el registro representado por \"self\".\n"
+"Dispara la acción si es verdadera."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2825,6 +2976,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar instalaciones/actualizaciones pendientes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -2901,6 +3056,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Gráfico"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Acción de ventana"
@@ -3015,9 +3174,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Francés"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Búlgaro"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3071,36 +3231,52 @@ msgctxt "model:ir.model.print_model_graph.start,name:"
 msgid "Print Model Graph"
 msgstr "Imprimir gráfico de modelos"
 
+#, fuzzy
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Finalización asistente de configuración de módulos"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Asistente de configuración del módulo - Primero"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Asistente de configuración después de instalar un módulo"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Otro asistente de configuración del módulo"
 
+#, fuzzy
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Dependencias del módulo"
 
+#, fuzzy
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Finalización instalación o actualización de módulos"
 
+#, fuzzy
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Iniciar la instalación o actualización de módulos"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3283,6 +3459,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propiedades"
@@ -3443,57 +3623,70 @@ msgctxt "selection:ir.lang,direction:"
 msgid "Right-to-left"
 msgstr "De derecha a izquierda"
 
+#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Instalado"
 
+#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "No instalado"
 
+#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Para instalar"
 
+#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Para eliminar"
 
+#, fuzzy
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Para actualizar"
 
+#, fuzzy
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Realizado"
 
+#, fuzzy
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Pendiente"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Instalado"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "No instalado"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Para instalar"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Para eliminar"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Para actualizar"
 
+#, fuzzy
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Desconocido"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3535,9 +3728,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Informes"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3595,21 +3789,25 @@ msgctxt "selection:ir.ui.view,type:"
 msgid "Tree"
 msgstr "Árbol"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domain"
-msgstr ""
+msgstr "Dominio"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domains"
-msgstr ""
+msgstr "Dominios"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.view:"
 msgid "View"
-msgstr ""
+msgstr "Vista"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.view:"
 msgid "Views"
-msgstr ""
+msgstr "Vistas"
 
 msgctxt "view:ir.action.act_window:"
 msgid "General"
@@ -3623,21 +3821,24 @@ msgctxt "view:ir.action.act_window:"
 msgid "Open a Window"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.keyword:"
 msgid "Keyword"
-msgstr ""
+msgstr "Acción de teclado"
 
+#, fuzzy
 msgctxt "view:ir.action.keyword:"
 msgid "Keywords"
-msgstr ""
+msgstr "Acciones de teclado"
 
 msgctxt "view:ir.action.report:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.report:"
 msgid "Report"
-msgstr ""
+msgstr "Informes"
 
 msgctxt "view:ir.action.report:"
 msgid "Report xml"
@@ -3647,61 +3848,75 @@ msgctxt "view:ir.action.url:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.url:"
 msgid "URL"
-msgstr ""
+msgstr "URLs"
 
 msgctxt "view:ir.action.wizard:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.wizard:"
 msgid "Wizard"
-msgstr ""
+msgstr "Asistentes"
 
+#, fuzzy
 msgctxt "view:ir.action:"
 msgid "Action"
-msgstr ""
+msgstr "Acción"
 
 msgctxt "view:ir.action:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Attachments"
-msgstr ""
+msgstr "Adjuntos"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Última modificación"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
-msgid "Scheduled Action"
+msgid "Run Once"
 msgstr ""
 
+#, fuzzy
+msgctxt "view:ir.cron:"
+msgid "Scheduled Action"
+msgstr "Acciones planificadas"
+
+#, fuzzy
 msgctxt "view:ir.cron:"
 msgid "Scheduled Actions"
-msgstr ""
+msgstr "Acciones planificadas"
 
+#, fuzzy
 msgctxt "view:ir.export:"
 msgid "Exports"
-msgstr ""
+msgstr "Exportaciones"
 
 msgctxt "view:ir.lang:"
 msgid "Date Formatting"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.lang:"
 msgid "Language"
-msgstr ""
+msgstr "Idioma"
 
+#, fuzzy
 msgctxt "view:ir.lang:"
 msgid "Languages"
-msgstr ""
+msgstr "Idiomas"
 
 msgctxt "view:ir.lang:"
 msgid "Numbers Formatting"
@@ -3711,45 +3926,54 @@ msgctxt "view:ir.model.access:"
 msgid "Access controls"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.button:"
 msgid "Button"
-msgstr ""
+msgstr "Botones"
 
+#, fuzzy
 msgctxt "view:ir.model.button:"
 msgid "Buttons"
-msgstr ""
+msgstr "Botones"
 
+#, fuzzy
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "Datos del modelo"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.field.access:"
 msgid "Field Access"
-msgstr ""
+msgstr "Permiso de los campos"
 
+#, fuzzy
 msgctxt "view:ir.model.field:"
 msgid "Field"
-msgstr ""
+msgstr "Campo"
 
+#, fuzzy
 msgctxt "view:ir.model.field:"
 msgid "Fields"
-msgstr ""
+msgstr "Campos"
 
+#, fuzzy
 msgctxt "view:ir.model.print_model_graph.start:"
 msgid "Print Model Graph"
-msgstr ""
+msgstr "Imprimir gráfico de modelos"
 
+#, fuzzy
 msgctxt "view:ir.model:"
 msgid "Model Description"
-msgstr ""
+msgstr "Descripción modelo"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Configuración del módulo"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
@@ -3765,21 +3989,24 @@ msgid ""
 " have installed."
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Asistente de configuración"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dependencias"
 
+#, fuzzy
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Dependencias"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
@@ -3825,42 +4052,72 @@ msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Módulo"
 
+#, fuzzy
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Módulos"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Fecha"
+
+msgctxt "view:ir.note:"
+msgid "Note"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuario"
+
+#, fuzzy
 msgctxt "view:ir.property:"
 msgid "Properties"
-msgstr ""
+msgstr "Propiedades"
 
+#, fuzzy
 msgctxt "view:ir.property:"
 msgid "Property"
-msgstr ""
+msgstr "Propiedades"
 
 msgctxt "view:ir.rule.group:"
 msgid ""
 "If there is no test defined, the rule is always satisfied if not global"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.rule.group:"
 msgid "Record rules"
-msgstr ""
+msgstr "Reglas de registros"
 
+#, fuzzy
 msgctxt "view:ir.rule.group:"
 msgid "The rule is satisfied if at least one test is True"
-msgstr ""
+msgstr "La regla es correcta si al menos una condición es cierta."
 
+#, fuzzy
 msgctxt "view:ir.rule:"
 msgid "Test"
-msgstr ""
+msgstr "Tests"
 
+#, fuzzy
 msgctxt "view:ir.sequence.type:"
 msgid "Sequence Type"
-msgstr ""
+msgstr "Tipos de secuencia"
 
 msgctxt "view:ir.sequence:"
 msgid "${day}"
@@ -3874,141 +4131,170 @@ msgctxt "view:ir.sequence:"
 msgid "${year}"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Day:"
-msgstr ""
+msgstr "Días"
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Incremental"
-msgstr ""
+msgstr "Incremental"
 
 msgctxt "view:ir.sequence:"
 msgid "Legend (Placeholders for prefix, suffix)"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Month:"
-msgstr ""
+msgstr "Meses"
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Sequences"
-msgstr ""
+msgstr "Secuencias"
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Timestamp"
-msgstr ""
+msgstr "Fecha-hora"
 
 msgctxt "view:ir.sequence:"
 msgid "Year:"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "Limpiar traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations?"
-msgstr ""
+msgstr "Limpiar traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "Limpiar traducciones"
 
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.export.result:"
 msgid "Export Translation"
-msgstr ""
+msgstr "Exportar traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
-msgstr ""
+msgstr "Exportar traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Definir traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
-msgstr ""
+msgstr "Sincronizar traducciones"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Definir traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation.update.start:"
 msgid "Synchronize Translations"
-msgstr ""
+msgstr "Sincronizar traducciones"
 
+#, fuzzy
 msgctxt "view:ir.translation:"
 msgid "Translations"
-msgstr ""
+msgstr "Traducciones"
 
+#, fuzzy
 msgctxt "view:ir.trigger:"
 msgid "Trigger"
-msgstr ""
+msgstr "Disparador"
 
+#, fuzzy
 msgctxt "view:ir.trigger:"
 msgid "Triggers"
-msgstr ""
+msgstr "Disparadores"
 
+#, fuzzy
 msgctxt "view:ir.ui.icon:"
 msgid "Icon"
-msgstr ""
+msgstr "Icono"
 
+#, fuzzy
 msgctxt "view:ir.ui.icon:"
 msgid "Icons"
-msgstr ""
+msgstr "Iconos"
 
+#, fuzzy
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorite"
-msgstr ""
+msgstr "Menú favorito"
 
+#, fuzzy
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorites"
-msgstr ""
+msgstr "Menú favorito"
 
+#, fuzzy
 msgctxt "view:ir.ui.menu:"
 msgid "Menu"
-msgstr ""
+msgstr "Menú"
 
 msgctxt "view:ir.ui.view:"
 msgid "Show"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "View"
-msgstr ""
+msgstr "Vista"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_search:"
 msgid "View Search"
-msgstr ""
+msgstr "Búsquedas favoritas"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
-msgstr ""
+msgstr "Búsquedas favoritas"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Estado vista árbol"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "Estado vista árbol"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
-msgstr ""
+msgstr "Ancho vista de árbol"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "Views Tree Width"
-msgstr ""
+msgstr "Ancho vista de árbol"
 
 msgctxt "wizard_button:ir.model.print_model_graph,start,end:"
 msgid "Cancel"
@@ -4018,37 +4304,45 @@ msgctxt "wizard_button:ir.model.print_model_graph,start,print_:"
 msgid "Print"
 msgstr "Imprimir"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Siguiente"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "Aceptar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Iniciar actualización"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/fr_FR.po b/trytond/ir/locale/fr_FR.po
index f46a678..04b6abf 100644
--- a/trytond/ir/locale/fr_FR.po
+++ b/trytond/ir/locale/fr_FR.po
@@ -72,8 +72,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Définition de mail incorrecte sur le rapport « %s »."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 "Le nom des pièces jointes doivent être unique pour une même ressource !"
 
@@ -434,6 +435,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valeur du contexte"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Date de création"
@@ -1686,6 +1691,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Modules à mettre à jour"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Date de création"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Créé par"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Dernière modification"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Dernier utilisateur"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nom"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Ressource"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Date de mise à jour"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Mis à jour par"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Date de création"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Créé par"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nom"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Utilisateur"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Date de mise à jour"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Mis à jour par"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Date de création"
@@ -2846,6 +2947,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Lancer les installations/mise à jours en attente"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propriétés"
@@ -2922,6 +3027,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Graphique"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Action ouvrir fenêtre"
@@ -3124,6 +3233,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Installation Mise à jour de module - Début"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Propriété"
@@ -3304,6 +3421,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Modules"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propriétés"
@@ -3556,9 +3677,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modèle"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Rapport"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3701,6 +3823,10 @@ msgid "Action to trigger"
 msgstr "Action à déclencher"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Action planifiée"
 
@@ -3856,6 +3982,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Modules"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Date"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Utilisateur"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propriétés"
diff --git a/trytond/ir/locale/hu_HU.po b/trytond/ir/locale/hu_HU.po
index e5e0389..9e1e786 100644
--- a/trytond/ir/locale/hu_HU.po
+++ b/trytond/ir/locale/hu_HU.po
@@ -70,8 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Érvénytelen e-mail cím a jelentésben \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "A nevet egy mellékletnek csak egyszer adható meg!"
 
 msgctxt "error:ir.cron:"
@@ -164,23 +165,23 @@ msgstr "A minta csak egyszer adható."
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "A modul függősége egyértelműnek kell lenni!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Hiányzó függőség %s  a \"%s\" a \"%s\" modulnak."
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
-msgstr ""
+msgstr "A törölni kívánt modulok a telepített moduloktól függenek:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "Egy modul neve csak egyszer adható."
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "A már telepített vagy telepítésre előjegyzett modul nem törölhető."
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -246,11 +247,14 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"Időzített\" a többi opció egymást kizárja!"
 
+#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
+"A Tigger \"%(trigger)s\" feltételei  \"%(condition)s\" nem érvényes Python "
+"kifejezés."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -412,6 +416,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Összefüggés"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Létrehozás dátuma"
@@ -1518,152 +1526,248 @@ msgstr "Szint"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Alárendelt (modul)"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Létrehozás dátuma"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Által létrehozva"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Függőségek"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Név"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Fölérendelt (modul)"
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Név"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Státusz"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Verzió"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Utolsó módosítás dátuma"
 
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Által módosítva"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Művelet"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Létrehozás dátuma"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Által létrehozva"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Név"
 
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Sorrend"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Státusz"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Utolsó módosítás dátuma"
 
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Által módosítva"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Százalék:"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Létrehozás dátuma"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Által létrehozva"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Modul"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Név"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Név"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Státusz"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Utolsó módosítás dátuma"
 
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Által módosítva"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Aktualizálásra váró modulok"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Létrehozás dátuma"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Által létrehozva"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Utolsó módosítás"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Utolsó használó"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Név"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Forrás"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Utolsó módosítás dátuma"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Által módosítva"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Létrehozás dátuma"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Által létrehozva"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Név"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Felhasználó"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Utolsó módosítás dátuma"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Által módosítva"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Létrehozás dátuma"
@@ -2698,11 +2802,13 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "A szabály akkor érvényes, ha legalább egy teszt pozitív"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Python kifejezés, mely az adattal (\"self\"által képviselve)van értékelve."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2820,6 +2926,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Előjegyzett installációk/aktualizálás végrehajtása"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Tulajdonságok"
@@ -2896,13 +3006,18 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Grafikon"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Művelet aktív ablak"
 
+#, fuzzy
 msgctxt "model:ir.action.act_window.domain,name:"
 msgid "Action act window domain"
-msgstr ""
+msgstr "Aktív ablak nézet"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_model_data_form_domain_all"
@@ -3010,9 +3125,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Francia"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Bolgár"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3068,34 +3184,42 @@ msgstr "Grafikon nyomtatása"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Modul"
 
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Modulkonfigurációs wizard befejezve"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Konfigurációs wizard első modul "
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Konfigurációs wizard modul telepítés után"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Konfigurációs wizard más modul"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Modultól függő"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Modul telepítésének aktualizálása megtörtént"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Modul telepítésének aktualizálása indít"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3278,6 +3402,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Modulok"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Tulajdonságok"
@@ -3370,9 +3498,10 @@ msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
 msgstr "Keresés nézet"
 
+#, fuzzy
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Oszlop széles  nézet"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
@@ -3440,55 +3569,55 @@ msgstr "Jobbról balra"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Telepítve"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Nincs telepítve"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Telepítendő"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Eltávolítandó"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Frissítendő"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Kész"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Megnyit"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Telepítve"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Nincs telepítve"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Telepítendő"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Eltávolítandó"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Frissítendő"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Ismeretlen"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3530,9 +3659,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Minta"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Jelentések"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3592,19 +3722,19 @@ msgstr "Fa"
 
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domain"
-msgstr ""
+msgstr "Értéktartomány"
 
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domains"
-msgstr ""
+msgstr "Értéktartomány"
 
 msgctxt "view:ir.action.act_window.view:"
 msgid "View"
-msgstr ""
+msgstr "Nézet"
 
 msgctxt "view:ir.action.act_window.view:"
 msgid "Views"
-msgstr ""
+msgstr "Nézetek"
 
 msgctxt "view:ir.action.act_window:"
 msgid "General"
@@ -3620,19 +3750,20 @@ msgstr ""
 
 msgctxt "view:ir.action.keyword:"
 msgid "Keyword"
-msgstr ""
+msgstr "Kulcsszó"
 
 msgctxt "view:ir.action.keyword:"
 msgid "Keywords"
-msgstr ""
+msgstr "Kulcsszavak"
 
 msgctxt "view:ir.action.report:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.report:"
 msgid "Report"
-msgstr ""
+msgstr "Jelentések"
 
 msgctxt "view:ir.action.report:"
 msgid "Report xml"
@@ -3642,21 +3773,23 @@ msgctxt "view:ir.action.url:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.url:"
 msgid "URL"
-msgstr ""
+msgstr "URL"
 
 msgctxt "view:ir.action.wizard:"
 msgid "General"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.action.wizard:"
 msgid "Wizard"
-msgstr ""
+msgstr "Wizards"
 
 msgctxt "view:ir.action:"
 msgid "Action"
-msgstr ""
+msgstr "Művelet"
 
 msgctxt "view:ir.action:"
 msgid "General"
@@ -3664,27 +3797,33 @@ msgstr ""
 
 msgctxt "view:ir.attachment:"
 msgid "Attachments"
-msgstr ""
+msgstr "Mellékletek"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Utolsó módosítás"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
-msgid "Scheduled Action"
+msgid "Run Once"
 msgstr ""
 
+#, fuzzy
+msgctxt "view:ir.cron:"
+msgid "Scheduled Action"
+msgstr "Ütemezett műveletek"
+
 msgctxt "view:ir.cron:"
 msgid "Scheduled Actions"
-msgstr ""
+msgstr "Ütemezett műveletek"
 
 msgctxt "view:ir.export:"
 msgid "Exports"
-msgstr ""
+msgstr "Export"
 
 msgctxt "view:ir.lang:"
 msgid "Date Formatting"
@@ -3692,11 +3831,11 @@ msgstr ""
 
 msgctxt "view:ir.lang:"
 msgid "Language"
-msgstr ""
+msgstr "Nyelv"
 
 msgctxt "view:ir.lang:"
 msgid "Languages"
-msgstr ""
+msgstr "Nyelvek"
 
 msgctxt "view:ir.lang:"
 msgid "Numbers Formatting"
@@ -3706,45 +3845,49 @@ msgctxt "view:ir.model.access:"
 msgid "Access controls"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.button:"
 msgid "Button"
-msgstr ""
+msgstr "Gombok"
 
 msgctxt "view:ir.model.button:"
 msgid "Buttons"
-msgstr ""
+msgstr "Gombok"
 
+#, fuzzy
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "Minta adat"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.field.access:"
 msgid "Field Access"
-msgstr ""
+msgstr "Mező hozzáférésének engedélyezése"
 
 msgctxt "view:ir.model.field:"
 msgid "Field"
-msgstr ""
+msgstr "Mező"
 
 msgctxt "view:ir.model.field:"
 msgid "Fields"
-msgstr ""
+msgstr "Mezők"
 
 msgctxt "view:ir.model.print_model_graph.start:"
 msgid "Print Model Graph"
-msgstr ""
+msgstr "Grafikon nyomtatása"
 
 msgctxt "view:ir.model:"
 msgid "Model Description"
-msgstr ""
+msgstr "Minta leírás"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Modul konfiguráció"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
@@ -3762,7 +3905,7 @@ msgstr ""
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Wizardelemek konfigurációja"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
@@ -3770,11 +3913,12 @@ msgstr ""
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Függőségek"
 
+#, fuzzy
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Függőségek"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
@@ -3822,40 +3966,65 @@ msgstr ""
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Modul"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Modulok"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Dátum"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
 msgstr ""
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Felhasználó"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
-msgstr ""
+msgstr "Tulajdonságok"
 
 msgctxt "view:ir.property:"
 msgid "Property"
-msgstr ""
+msgstr "Tulajdonság"
 
 msgctxt "view:ir.rule.group:"
 msgid ""
 "If there is no test defined, the rule is always satisfied if not global"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.rule.group:"
 msgid "Record rules"
-msgstr ""
+msgstr "Adatszabályok"
 
 msgctxt "view:ir.rule.group:"
 msgid "The rule is satisfied if at least one test is True"
-msgstr ""
+msgstr "A szabály akkor érvényes, ha legalább egy teszt pozitív"
 
+#, fuzzy
 msgctxt "view:ir.rule:"
 msgid "Test"
-msgstr ""
+msgstr "Teszt"
 
+#, fuzzy
 msgctxt "view:ir.sequence.type:"
 msgid "Sequence Type"
-msgstr ""
+msgstr "Számkör típus"
 
 msgctxt "view:ir.sequence:"
 msgid "${day}"
@@ -3869,29 +4038,31 @@ msgctxt "view:ir.sequence:"
 msgid "${year}"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Day:"
-msgstr ""
+msgstr "Nap"
 
 msgctxt "view:ir.sequence:"
 msgid "Incremental"
-msgstr ""
+msgstr "Inkrementális"
 
 msgctxt "view:ir.sequence:"
 msgid "Legend (Placeholders for prefix, suffix)"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.sequence:"
 msgid "Month:"
-msgstr ""
+msgstr "Hónap"
 
 msgctxt "view:ir.sequence:"
 msgid "Sequences"
-msgstr ""
+msgstr "Számkör"
 
 msgctxt "view:ir.sequence:"
 msgid "Timestamp"
-msgstr ""
+msgstr "Időbélyeg"
 
 msgctxt "view:ir.sequence:"
 msgid "Year:"
@@ -3899,35 +4070,39 @@ msgstr ""
 
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "Fordítások rendezése"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations?"
-msgstr ""
+msgstr "Fordítások rendezése"
 
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "Fordítások rendezése"
 
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.export.result:"
 msgid "Export Translation"
-msgstr ""
+msgstr "Fordítások exportálása"
 
+#, fuzzy
 msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
-msgstr ""
+msgstr "Fordítások exportálása"
 
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Fordítás aktualizálása"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
-msgstr ""
+msgstr "Fordítás megadás"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
@@ -3935,43 +4110,44 @@ msgstr ""
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Fordítás aktualizálása"
 
 msgctxt "view:ir.translation.update.start:"
 msgid "Synchronize Translations"
-msgstr ""
+msgstr "Fordítás megadás"
 
 msgctxt "view:ir.translation:"
 msgid "Translations"
-msgstr ""
+msgstr "Fordítások"
 
 msgctxt "view:ir.trigger:"
 msgid "Trigger"
-msgstr ""
+msgstr "Trigger"
 
 msgctxt "view:ir.trigger:"
 msgid "Triggers"
-msgstr ""
+msgstr "Trigger"
 
 msgctxt "view:ir.ui.icon:"
 msgid "Icon"
-msgstr ""
+msgstr "Ikon"
 
 msgctxt "view:ir.ui.icon:"
 msgid "Icons"
-msgstr ""
+msgstr "Ikonok"
 
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorite"
-msgstr ""
+msgstr "Kedvencek"
 
+#, fuzzy
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorites"
-msgstr ""
+msgstr "Kedvencek"
 
 msgctxt "view:ir.ui.menu:"
 msgid "Menu"
-msgstr ""
+msgstr "Menü"
 
 msgctxt "view:ir.ui.view:"
 msgid "Show"
@@ -3979,31 +4155,35 @@ msgstr ""
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
-msgstr ""
+msgstr "Nézet"
 
 msgctxt "view:ir.ui.view_search:"
 msgid "View Search"
-msgstr ""
+msgstr "Nézet keresés"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
-msgstr ""
+msgstr "Nézet keresés"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Oszlop széles  nézet"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "Oszlop széles  nézet"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
-msgstr ""
+msgstr "Oszlop széles  nézet"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "Views Tree Width"
-msgstr ""
+msgstr "Oszlop széles  nézet"
 
 msgctxt "wizard_button:ir.model.print_model_graph,start,end:"
 msgid "Cancel"
@@ -4015,35 +4195,35 @@ msgstr "Nyomtatás"
 
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "OK"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "OK"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Mégse"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Tovább"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Mégse"
 
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "OK"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Mégse"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Start"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/it_IT.po b/trytond/ir/locale/it_IT.po
index fea1d5b..63ce554 100644
--- a/trytond/ir/locale/it_IT.po
+++ b/trytond/ir/locale/it_IT.po
@@ -42,6 +42,8 @@ msgstr "Il valore \"%(value)s del campo \"%(field)s\" in \"(model)s\" non esiste
 msgctxt "error:ir.action.act_window.domain:"
 msgid "Invalid domain or search criteria \"%(domain)s\" on action \"%(action)s\"."
 msgstr ""
+"Dominio o criterio di ricerca \"%(domain)s\" invalido nell'azione "
+"\"%(action)s\"."
 
 msgctxt "error:ir.action.act_window:"
 msgid "Invalid context \"%(context)s\" on action \"%(action)s\"."
@@ -65,8 +67,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Definizione dell'email invalida nel report \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "Il nome degli allegati dev'essere unico per risorsa"
 
 msgctxt "error:ir.cron:"
@@ -159,11 +162,11 @@ msgstr "Il modello dev'essere unico"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "La dipendenza dev'essere unica per modulo"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Mancano le dipendenze %s per il modulo \"%s\""
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
@@ -171,11 +174,11 @@ msgstr ""
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "Il nome del modulo dev'essere unico"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "Non si può rimuovere un modulo che viene o verrà installato"
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -246,11 +249,15 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"On Time\" e others si escludono a vicenda"
 
+#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
+"La condizione \"%(condition)s\" non "
+"è "
+"un'epressione python valida per il trigger \"%(trigger)s\"."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -433,6 +440,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valore Contenuto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Creazione Data"
@@ -1621,152 +1632,259 @@ msgstr "Livello"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Figli"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Creazione Data"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creazione Utente"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dipendenze"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nome"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Padri"
 
+#, fuzzy
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nome"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Stato"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Versione"
 
+#, fuzzy
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Data di Scrittura"
 
+#, fuzzy
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Scrivente"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Azione"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Creazione Data"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creazione Utente"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nome"
 
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Sequenza"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Stato"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Data di Scrittura"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Scrivente"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Percentuale"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Creazione Data"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Creazione Utente"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Modulo"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Nome"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Nome"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Stato"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Data di Scrittura"
 
+#, fuzzy
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Scrivente"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Moduli da aggiornare"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Creazione Data"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Creazione Utente"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Ultima Modifica"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Ultimo utente"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nome"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Risorsa"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Data di Scrittura"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Scrivente"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Creazione Data"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Creazione Utente"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nome"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Utente"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Data di Scrittura"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Scrivente"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Creazione Data"
@@ -2323,7 +2441,7 @@ msgstr "Numero Limite"
 
 msgctxt "field:ir.trigger,minimum_time_delay:"
 msgid "Minimum Delay"
-msgstr ""
+msgstr "Ritardo minimo"
 
 msgctxt "field:ir.trigger,model:"
 msgid "Model"
@@ -2872,11 +2990,12 @@ msgstr ""
 "La regola è rispettata se almeno uno "
 "è True"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
-msgstr ""
+msgstr "Istruzione Python con record rappresentato da \"self\""
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2884,11 +3003,14 @@ msgid ""
 "0 for no limit."
 msgstr "Limitare per record il numero delle call ad \"Action Functions\""
 
+#, fuzzy
 msgctxt "help:ir.trigger,minimum_time_delay:"
 msgid ""
 "Set a minimum time delay between call to \"Action Function\" for the same record.\n"
 "empty for no delay."
 msgstr ""
+"Imposta un ritardo minimo fra le call ad \"Action Function\" per la stesso "
+"record. 0 per nessun ritardo"
 
 msgctxt "help:ir.ui.view_search,domain:"
 msgid "The PYSON domain"
@@ -2990,6 +3112,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Procedere con l'installazione o l'upgrade in sospeso"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Proprietà"
@@ -3066,6 +3192,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Grafo"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Finestra Action act"
@@ -3181,9 +3311,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Francese"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Bulgaro"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3239,34 +3370,42 @@ msgstr "Stampa modello grafico"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Modulo"
 
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Wizard di config modulo Fatto"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Wizard di config modulo primo"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Lanciare il wizard di configurazione dopo l'installazione del modulo"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Wizard di config modulo Altro"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Dipendenza Modulo"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Installazione Upgrade Modulo Fatto"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Installazione Upgrade Modulo "
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3449,6 +3588,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Moduli"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Proprietà"
@@ -3611,55 +3754,55 @@ msgstr "Destra-Sinistra"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Installato"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Non Installato"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Da installare"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Da rimuovere"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Da upgradare"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Fatto"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Apertura"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Installato"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Non Installato"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Da installare"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Da rimuovere"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Da upgradare"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "URLs"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3701,9 +3844,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modello"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Report"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3837,15 +3981,20 @@ msgctxt "view:ir.attachment:"
 msgid "Attachments"
 msgstr "Allegati"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Ultima Modifica"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr "Trigger Azione"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Azione pianificata"
 
@@ -3916,41 +4065,42 @@ msgstr "Descrizione Modello"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Configurazione Modulo"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
-msgstr ""
+msgstr "Configurazione effettuata"
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "Benvenuto al wizard di configurazione del modulo"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
-msgstr ""
+msgstr "Installazione configurabile dall'utente in base ai moduli installati"
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Elementi per wizard di configurazione"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
-msgstr ""
+msgstr "Prossimo step del wizard di configurazione"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Dipendenze"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Dipendenza"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
-msgstr ""
+msgstr "Upgrade del sistema effettuato"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
@@ -3958,48 +4108,70 @@ msgstr ""
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
-msgstr ""
+msgstr "Questa operazione potrebbe durare qualche minuto"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "System Upgrade"
-msgstr ""
+msgstr "Upgrade del sistema"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Your system will be upgraded."
-msgstr ""
+msgstr "Il sistema verrà upgradato"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "Cancellare l'installazione"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "Cancellare la rimozione"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "Cancellare l'upgrade"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "Seleziona per installare"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "Seleziona per disinstallare (beta)"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "Seleziona per upgrade"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Modulo"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Moduli"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Data"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Utente"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Proprietà"
@@ -4149,9 +4321,10 @@ msgctxt "view:ir.ui.menu:"
 msgid "Menu"
 msgstr "Menu"
 
+#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr ""
+msgstr "_Show"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
@@ -4199,15 +4372,15 @@ msgstr ""
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancella"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Prossimo"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancella"
 
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
@@ -4215,11 +4388,11 @@ msgstr ""
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Cancella"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Avvia l'upgrade"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/ja_JP.po b/trytond/ir/locale/ja_JP.po
index d71a1fa..d5b3532 100644
--- a/trytond/ir/locale/ja_JP.po
+++ b/trytond/ir/locale/ja_JP.po
@@ -59,7 +59,7 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 
 msgctxt "error:ir.cron:"
@@ -383,6 +383,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr ""
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -1635,6 +1639,86 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr ""
 
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr ""
+
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr ""
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr ""
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr ""
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -2777,6 +2861,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr ""
@@ -2853,6 +2941,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr ""
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr ""
@@ -3055,6 +3147,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr ""
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr ""
@@ -3235,6 +3335,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr ""
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr ""
@@ -3488,7 +3592,7 @@ msgid "Model"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
+msgid "Report"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
@@ -3632,6 +3736,10 @@ msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr ""
 
@@ -3785,6 +3893,26 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr ""
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr ""
diff --git a/trytond/ir/locale/lt_LT.po b/trytond/ir/locale/lo_LA.po
similarity index 93%
copy from trytond/ir/locale/lt_LT.po
copy to trytond/ir/locale/lo_LA.po
index d71a1fa..0ecec68 100644
--- a/trytond/ir/locale/lt_LT.po
+++ b/trytond/ir/locale/lo_LA.po
@@ -59,7 +59,7 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 
 msgctxt "error:ir.cron:"
@@ -327,17 +327,19 @@ msgctxt "field:ir.action,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.action,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action,keywords:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "field:ir.action,name:"
 msgid "Name"
@@ -349,7 +351,7 @@ msgstr ""
 
 msgctxt "field:ir.action,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.action,usage:"
 msgid "Usage"
@@ -367,9 +369,10 @@ msgctxt "field:ir.action.act_window,act_window_domains:"
 msgid "Domains"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,act_window_views:"
 msgid "Views"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "field:ir.action.act_window,action:"
 msgid "Action"
@@ -383,6 +386,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr ""
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -403,17 +410,19 @@ msgctxt "field:ir.action.act_window,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.action.act_window,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,keywords:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "field:ir.action.act_window,limit:"
 msgid "Limit"
@@ -455,17 +464,19 @@ msgctxt "field:ir.action.act_window,search_value:"
 msgid "Search Criteria"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.action.act_window,usage:"
 msgid "Usage"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,views:"
 msgid "Views"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "field:ir.action.act_window,window_name:"
 msgid "Window Name"
@@ -551,9 +562,10 @@ msgctxt "field:ir.action.act_window.view,sequence:"
 msgid "Sequence"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window.view,view:"
 msgid "View"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "field:ir.action.act_window.view,write_date:"
 msgid "Write Date"
@@ -583,9 +595,10 @@ msgctxt "field:ir.action.keyword,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.keyword,keyword:"
 msgid "Keyword"
-msgstr ""
+msgstr "ຄຳລະຫັດ"
 
 msgctxt "field:ir.action.keyword,model:"
 msgid "Model"
@@ -635,17 +648,19 @@ msgctxt "field:ir.action.report,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.report,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.action.report,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.report,keywords:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "field:ir.action.report,model:"
 msgid "Model"
@@ -691,9 +706,10 @@ msgctxt "field:ir.action.report,template_extension:"
 msgid "Template Extension"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.report,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.action.report,usage:"
 msgid "Usage"
@@ -727,17 +743,19 @@ msgctxt "field:ir.action.url,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.url,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.action.url,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.url,keywords:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "field:ir.action.url,name:"
 msgid "Name"
@@ -747,9 +765,10 @@ msgctxt "field:ir.action.url,rec_name:"
 msgid "Name"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.url,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.action.url,url:"
 msgid "Action Url"
@@ -791,17 +810,19 @@ msgctxt "field:ir.action.wizard,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.wizard,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.action.wizard,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.wizard,keywords:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "field:ir.action.wizard,model:"
 msgid "Model"
@@ -815,9 +836,10 @@ msgctxt "field:ir.action.wizard,rec_name:"
 msgid "Name"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.wizard,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.action.wizard,usage:"
 msgid "Usage"
@@ -899,9 +921,10 @@ msgctxt "field:ir.attachment,summary:"
 msgid "Summary"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.attachment,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.attachment,write_date:"
 msgid "Write Date"
@@ -1055,9 +1078,10 @@ msgctxt "field:ir.export,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.export,export_fields:"
 msgid "Fields"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "field:ir.export,id:"
 msgid "ID"
@@ -1183,9 +1207,10 @@ msgctxt "field:ir.model,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.model,fields:"
 msgid "Fields"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "field:ir.model,global_search_p:"
 msgid "Global Search"
@@ -1435,9 +1460,10 @@ msgctxt "field:ir.model.field.access,description:"
 msgid "Description"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.model.field.access,field:"
 msgid "Field"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "field:ir.model.field.access,group:"
 msgid "Group"
@@ -1635,6 +1661,86 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr ""
 
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr ""
+
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr ""
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr ""
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr ""
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -1643,9 +1749,10 @@ msgctxt "field:ir.property,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.property,field:"
 msgid "Field"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "field:ir.property,id:"
 msgid "ID"
@@ -1835,9 +1942,10 @@ msgctxt "field:ir.sequence,timestamp_rounding:"
 msgid "Timestamp Rounding"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.sequence,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.sequence,write_date:"
 msgid "Write Date"
@@ -1911,9 +2019,10 @@ msgctxt "field:ir.sequence.strict,timestamp_rounding:"
 msgid "Timestamp Rounding"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.sequence.strict,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.sequence.strict,write_date:"
 msgid "Write Date"
@@ -2063,9 +2172,10 @@ msgctxt "field:ir.translation,src_md5:"
 msgid "Source MD5"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.translation,type:"
 msgid "Type"
-msgstr ""
+msgstr "ປະເພດ"
 
 msgctxt "field:ir.translation,value:"
 msgid "Translation Value"
@@ -2235,9 +2345,10 @@ msgctxt "field:ir.ui.icon,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.icon,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.ui.icon,id:"
 msgid "ID"
@@ -2307,17 +2418,19 @@ msgctxt "field:ir.ui.menu,groups:"
 msgid "Groups"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.menu,icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "field:ir.ui.menu,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.menu,name:"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
 msgctxt "field:ir.ui.menu,parent:"
 msgid "Parent Menu"
@@ -2351,9 +2464,10 @@ msgctxt "field:ir.ui.menu.favorite,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.menu.favorite,menu:"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
 msgctxt "field:ir.ui.menu.favorite,rec_name:"
 msgid "Name"
@@ -2539,9 +2653,10 @@ msgctxt "field:ir.ui.view_tree_width,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.view_tree_width,field:"
 msgid "Field"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "field:ir.ui.view_tree_width,id:"
 msgid "ID"
@@ -2705,9 +2820,10 @@ msgctxt "model:ir.action,name:act_action_wizard_form"
 msgid "Wizards"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_attachment_form"
 msgid "Attachments"
-msgstr ""
+msgstr "ເອກະສານຄັດຕິດ"
 
 msgctxt "model:ir.action,name:act_config_wizard_item_form"
 msgid "Config Wizard Items"
@@ -2721,29 +2837,33 @@ msgctxt "model:ir.action,name:act_export_form"
 msgid "Exports"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "model:ir.action,name:act_lang_form"
 msgid "Languages"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_menu_list"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_menu_tree"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
 msgctxt "model:ir.action,name:act_model_access_form"
 msgid "Models Access"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_model_button_form"
 msgid "Buttons"
-msgstr ""
+msgstr "ປຸ່ມ"
 
 msgctxt "model:ir.action,name:act_model_data_form"
 msgid "Data"
@@ -2753,9 +2873,10 @@ msgctxt "model:ir.action,name:act_model_field_access_form"
 msgid "Fields Access"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_model_fields_form"
 msgid "Fields"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "model:ir.action,name:act_model_form"
 msgid "Models"
@@ -2777,6 +2898,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr ""
@@ -2801,13 +2926,14 @@ msgctxt "model:ir.action,name:act_sequence_type_form"
 msgid "Sequence Types"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_translation_clean"
 msgid "Clean Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
 msgctxt "model:ir.action,name:act_translation_export"
 msgid "Export Translations"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
 msgctxt "model:ir.action,name:act_translation_form"
 msgid "Translations"
@@ -2825,9 +2951,10 @@ msgctxt "model:ir.action,name:act_trigger_form"
 msgid "Triggers"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_view_form"
 msgid "Views"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "model:ir.action,name:act_view_search"
 msgid "View Search"
@@ -2853,6 +2980,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr ""
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr ""
@@ -2891,9 +3022,10 @@ msgctxt "model:ir.action.wizard,name:"
 msgid "Action wizard"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.attachment,name:"
 msgid "Attachment"
-msgstr ""
+msgstr "ເອກະສານຄັດຕິດ"
 
 msgctxt "model:ir.cache,name:"
 msgid "Cache"
@@ -3055,6 +3187,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr ""
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr ""
@@ -3091,21 +3231,25 @@ msgctxt "model:ir.translation,name:"
 msgid "Translation"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.translation.clean.start,name:"
 msgid "Clean translation"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
+#, fuzzy
 msgctxt "model:ir.translation.clean.succeed,name:"
 msgid "Clean translation"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
+#, fuzzy
 msgctxt "model:ir.translation.export.result,name:"
 msgid "Export translation"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
+#, fuzzy
 msgctxt "model:ir.translation.export.start,name:"
 msgid "Export translation"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
 msgctxt "model:ir.translation.set.start,name:"
 msgid "Set Translation"
@@ -3127,9 +3271,10 @@ msgctxt "model:ir.trigger.log,name:"
 msgid "Trigger Log"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.icon,name:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "model:ir.ui.menu,name:"
 msgid "UI menu"
@@ -3163,9 +3308,10 @@ msgctxt "model:ir.ui.menu,name:menu_administration"
 msgid "Administration"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_attachment_form"
 msgid "Attachments"
-msgstr ""
+msgstr "ເອກະສານຄັດຕິດ"
 
 msgctxt "model:ir.ui.menu,name:menu_config_wizard_item_form"
 msgid "Config Wizard Items"
@@ -3179,9 +3325,10 @@ msgctxt "model:ir.ui.menu,name:menu_export_form"
 msgid "Exports"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "model:ir.ui.menu,name:menu_ir_sequence_type"
 msgid "Sequence Types"
@@ -3195,17 +3342,19 @@ msgctxt "model:ir.ui.menu,name:menu_localization"
 msgid "Localization"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_menu_list"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
 msgctxt "model:ir.ui.menu,name:menu_model_access_form"
 msgid "Models Access"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_model_button_form"
 msgid "Buttons"
-msgstr ""
+msgstr "ປຸ່ມ"
 
 msgctxt "model:ir.ui.menu,name:menu_model_data_form"
 msgid "Data"
@@ -3235,6 +3384,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr ""
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr ""
@@ -3263,21 +3416,24 @@ msgctxt "model:ir.ui.menu,name:menu_sequences"
 msgid "Sequences"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_translation_clean"
 msgid "Clean Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_translation_export"
 msgid "Export Translations"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_form"
 msgid "Translations"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_translation_set"
 msgid "Set Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_update"
 msgid "Synchronize Translations"
@@ -3291,9 +3447,10 @@ msgctxt "model:ir.ui.menu,name:menu_ui"
 msgid "User Interface"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_view"
 msgid "Views"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "model:ir.ui.menu,name:menu_view_search"
 msgid "View Search"
@@ -3307,17 +3464,19 @@ msgctxt "model:ir.ui.menu,name:menu_view_tree_width"
 msgid "View Tree Width"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:model_model_fields_form"
 msgid "Fields"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "model:ir.ui.menu.favorite,name:"
 msgid "Menu Favorite"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.view,name:"
 msgid "View"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "model:ir.ui.view.show.start,name:"
 msgid "Show view"
@@ -3327,9 +3486,10 @@ msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "ສະຖານະເບິ່ງແບບຕົ້ນໄມ້"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
@@ -3475,9 +3635,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Error"
 msgstr ""
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "Field"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Help"
@@ -3488,16 +3649,17 @@ msgid "Model"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
+msgid "Report"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
 msgstr ""
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
 msgid "View"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Wizard Button"
@@ -3557,11 +3719,12 @@ msgstr ""
 
 msgctxt "view:ir.action.act_window.view:"
 msgid "View"
-msgstr ""
+msgstr "ເບິ່ງ"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.view:"
 msgid "Views"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "view:ir.action.act_window:"
 msgid "General"
@@ -3577,11 +3740,11 @@ msgstr ""
 
 msgctxt "view:ir.action.keyword:"
 msgid "Keyword"
-msgstr ""
+msgstr "ຄຳລະຫັດ"
 
 msgctxt "view:ir.action.keyword:"
 msgid "Keywords"
-msgstr ""
+msgstr "ຂໍ້ຄວາມຫຼັກ"
 
 msgctxt "view:ir.action.report:"
 msgid "General"
@@ -3621,7 +3784,7 @@ msgstr ""
 
 msgctxt "view:ir.attachment:"
 msgid "Attachments"
-msgstr ""
+msgstr "ເອກະສານຄັດຕິດ"
 
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
@@ -3632,6 +3795,10 @@ msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr ""
 
@@ -3663,13 +3830,14 @@ msgctxt "view:ir.model.access:"
 msgid "Access controls"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.button:"
 msgid "Button"
-msgstr ""
+msgstr "ປຸ່ມ"
 
 msgctxt "view:ir.model.button:"
 msgid "Buttons"
-msgstr ""
+msgstr "ປຸ່ມ"
 
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
@@ -3683,13 +3851,14 @@ msgctxt "view:ir.model.field.access:"
 msgid "Field Access"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.field:"
 msgid "Field"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "view:ir.model.field:"
 msgid "Fields"
-msgstr ""
+msgstr "ຟິນລ໌"
 
 msgctxt "view:ir.model.print_model_graph.start:"
 msgid "Print Model Graph"
@@ -3785,6 +3954,26 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr ""
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr ""
@@ -3856,31 +4045,36 @@ msgstr ""
 
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations?"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.export.result:"
 msgid "Export Translation"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
+#, fuzzy
 msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
-msgstr ""
+msgstr "ສົ່ງການແປອອກ"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
@@ -3890,9 +4084,10 @@ msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "ລ້າງການແປ"
 
 msgctxt "view:ir.translation.update.start:"
 msgid "Synchronize Translations"
@@ -3912,11 +4107,11 @@ msgstr ""
 
 msgctxt "view:ir.ui.icon:"
 msgid "Icon"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "view:ir.ui.icon:"
 msgid "Icons"
-msgstr ""
+msgstr "ໄອຄັອນ"
 
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorite"
@@ -3928,7 +4123,7 @@ msgstr ""
 
 msgctxt "view:ir.ui.menu:"
 msgid "Menu"
-msgstr ""
+msgstr "ລາຍການ"
 
 msgctxt "view:ir.ui.view:"
 msgid "Show"
@@ -3936,7 +4131,7 @@ msgstr ""
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
-msgstr ""
+msgstr "ເບິ່ງ"
 
 msgctxt "view:ir.ui.view_search:"
 msgid "View Search"
@@ -3948,11 +4143,12 @@ msgstr ""
 
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "ສະຖານະເບິ່ງແບບຕົ້ນໄມ້"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "ສະຖານະເບິ່ງແບບຕົ້ນໄມ້"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
diff --git a/trytond/ir/locale/lt_LT.po b/trytond/ir/locale/lt_LT.po
index d71a1fa..d5b3532 100644
--- a/trytond/ir/locale/lt_LT.po
+++ b/trytond/ir/locale/lt_LT.po
@@ -59,7 +59,7 @@ msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr ""
 
 msgctxt "error:ir.cron:"
@@ -383,6 +383,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr ""
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -1635,6 +1639,86 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr ""
 
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr ""
+
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr ""
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr ""
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr ""
+
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr ""
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -2777,6 +2861,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr ""
@@ -2853,6 +2941,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr ""
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr ""
@@ -3055,6 +3147,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr ""
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr ""
@@ -3235,6 +3335,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr ""
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr ""
@@ -3488,7 +3592,7 @@ msgid "Model"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
+msgid "Report"
 msgstr ""
 
 msgctxt "selection:ir.translation,type:"
@@ -3632,6 +3736,10 @@ msgid "Action to trigger"
 msgstr ""
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr ""
 
@@ -3785,6 +3893,26 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr ""
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr ""
diff --git a/trytond/ir/locale/nl_NL.po b/trytond/ir/locale/nl_NL.po
index 669c007..2625f11 100644
--- a/trytond/ir/locale/nl_NL.po
+++ b/trytond/ir/locale/nl_NL.po
@@ -2,11 +2,14 @@
 msgid ""
 msgstr "Content-Type: text/plain; charset=utf-8\n"
 
+#, fuzzy
 msgctxt "error:access_error:"
 msgid ""
 "You try to bypass an access rule.\n"
 "(Document type: %s)"
 msgstr ""
+"U probeert een toegangsregel te omzeilen!\n"
+"(Document type: %s)"
 
 msgctxt "error:delete_xml_record:"
 msgid "You are not allowed to delete this record."
@@ -58,8 +61,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr ""
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "De namen van de bijlagen moeten uniek zijn per bron!"
 
 msgctxt "error:ir.cron:"
@@ -111,9 +115,10 @@ msgctxt "error:ir.model.access:"
 msgid "You can not write in this document! (%s)"
 msgstr "U kunt dit document niet muteren! (%s)"
 
+#, fuzzy
 msgctxt "error:ir.model.button:"
 msgid "The button name in model must be unique!"
-msgstr ""
+msgstr "De veldnaam in het model moet uniek zijn!"
 
 msgctxt "error:ir.model.data:"
 msgid "The triple (fs_id, module, model) must be unique!"
@@ -145,23 +150,24 @@ msgstr "Het model moet uniek zijn!"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "Afhankelijkheid moet uniek zijn per module!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Afhankelijkheid %s ontbreekt voor module \"%s\""
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
 msgstr ""
+"De module die u wilt verwijderen is afhankelijk van geïnstalleerde modules:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "De naam van de module moet uniek zijn!"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "U kunt een module niet verwijderen als die geïnstalleerd is of wordt."
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -239,11 +245,14 @@ msgctxt "error:ir.ui.view:"
 msgid "Invalid XML for view \"%s\"."
 msgstr ""
 
+#, fuzzy
 msgctxt "error:read_error:"
 msgid ""
 "You try to read records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"U probeert items te lezen die niet meer bestaan!\n"
+"(Document type: %s)"
 
 msgctxt "error:recursion_error:"
 msgid ""
@@ -293,11 +302,14 @@ msgctxt "error:too_many_relations_found:"
 msgid "Too many relations found: %r in %s"
 msgstr "Te veel relaties gevonden: %r in %s"
 
+#, fuzzy
 msgctxt "error:write_error:"
 msgid ""
 "You try to write on records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"U probeert items te lezen die niet meer bestaan!\n"
+"(Document type: %s)"
 
 msgctxt "error:write_xml_record:"
 msgid "You are not allowed to modify this record."
@@ -364,9 +376,10 @@ msgctxt "field:ir.action,write_uid:"
 msgid "Write User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,act_window_domains:"
 msgid "Domains"
-msgstr ""
+msgstr "Domein"
 
 msgctxt "field:ir.action.act_window,act_window_views:"
 msgid "Views"
@@ -385,6 +398,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Samenhang waarde"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -397,9 +414,10 @@ msgctxt "field:ir.action.act_window,domain:"
 msgid "Domain Value"
 msgstr "Domein waarde"
 
+#, fuzzy
 msgctxt "field:ir.action.act_window,domains:"
 msgid "Domains"
-msgstr ""
+msgstr "Domein"
 
 #, fuzzy
 msgctxt "field:ir.action.act_window,groups:"
@@ -680,9 +698,10 @@ msgctxt "field:ir.action.report,name:"
 msgid "Name"
 msgstr "Naam bijlage"
 
+#, fuzzy
 msgctxt "field:ir.action.report,pyson_email:"
 msgid "PySON Email"
-msgstr ""
+msgstr "PySON domein"
 
 msgctxt "field:ir.action.report,rec_name:"
 msgid "Name"
@@ -889,9 +908,10 @@ msgctxt "field:ir.attachment,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.attachment,data:"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
 msgctxt "field:ir.attachment,data_size:"
 msgid "Data size"
@@ -995,9 +1015,10 @@ msgctxt "field:ir.configuration,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.configuration,language:"
 msgid "language"
-msgstr ""
+msgstr "Taal"
 
 #, fuzzy
 msgctxt "field:ir.configuration,rec_name:"
@@ -1554,7 +1575,7 @@ msgstr ""
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Afhankelijkheden"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
@@ -1562,7 +1583,7 @@ msgstr ""
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Naam"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
@@ -1570,15 +1591,15 @@ msgstr ""
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Naam"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Status"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Versie"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
@@ -1598,7 +1619,7 @@ msgstr ""
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Actie"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
@@ -1614,15 +1635,16 @@ msgstr ""
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Naam"
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Reeks"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Status"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
@@ -1636,9 +1658,10 @@ msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Percentage"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
@@ -1654,19 +1677,19 @@ msgstr ""
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Module"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Naam"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Naam"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Status"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
@@ -1688,6 +1711,90 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr ""
 
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr ""
+
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr ""
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Naam"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Middel"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr ""
+
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr ""
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Naam"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Gebruiker"
+
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr ""
+
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr ""
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr ""
@@ -2048,9 +2155,10 @@ msgctxt "field:ir.session.wizard,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.session.wizard,data:"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
 msgctxt "field:ir.session.wizard,id:"
 msgid "ID"
@@ -2341,9 +2449,10 @@ msgctxt "field:ir.ui.menu,action:"
 msgid "Action"
 msgstr "Actie"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu,action_keywords:"
 msgid "Action Keywords"
-msgstr ""
+msgstr "Actietrefwoord"
 
 msgctxt "field:ir.ui.menu,active:"
 msgid "Active"
@@ -2457,9 +2566,10 @@ msgctxt "field:ir.ui.view,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.ui.view,data:"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
 msgctxt "field:ir.ui.view,domain:"
 msgid "Domain"
@@ -2739,11 +2849,14 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "De regel is waar als tenminste aan één voorwaarde wordt voldaan"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Een Python uitdrukking gekoppeld aan item \"self\"\n"
+"Het start de actie als het waar is."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2803,9 +2916,10 @@ msgctxt "model:ir.action,name:act_export_form"
 msgid "Exports"
 msgstr "Export"
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "Icoon"
 
 msgctxt "model:ir.action,name:act_lang_form"
 msgid "Languages"
@@ -2828,13 +2942,15 @@ msgctxt "model:ir.action,name:act_model_button_form"
 msgid "Buttons"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_model_data_form"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
+#, fuzzy
 msgctxt "model:ir.action,name:act_model_field_access_form"
 msgid "Fields Access"
-msgstr ""
+msgstr "Leesrecht"
 
 msgctxt "model:ir.action,name:act_model_fields_form"
 msgid "Fields"
@@ -2860,6 +2976,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Voer installatie / bijwerken uit"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Eigenschappen"
@@ -2936,13 +3056,18 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Grafiek"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Actie uitvoerend scherm"
 
+#, fuzzy
 msgctxt "model:ir.action.act_window.domain,name:"
 msgid "Action act window domain"
-msgstr ""
+msgstr "Actie uitvoerend schermaanzicht"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_model_data_form_domain_all"
@@ -3109,34 +3234,45 @@ msgstr ""
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Module"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Module EHBC"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Module EHBC"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Configuratie assistent die start na installatie van de module"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Module EHBC"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Module afhankelijkheid"
 
+#, fuzzy
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Start module gaan bijwerken"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Start module gaan bijwerken"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3195,13 +3331,15 @@ msgctxt "model:ir.translation.export.start,name:"
 msgid "Export translation"
 msgstr "Vertaling exporteren - bestand"
 
+#, fuzzy
 msgctxt "model:ir.translation.set.start,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
+#, fuzzy
 msgctxt "model:ir.translation.set.succeed,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
 msgctxt "model:ir.translation.update.start,name:"
 msgid "Update translation"
@@ -3268,9 +3406,10 @@ msgctxt "model:ir.ui.menu,name:menu_export_form"
 msgid "Exports"
 msgstr "Export"
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "Icoon"
 
 msgctxt "model:ir.ui.menu,name:menu_ir_sequence_type"
 msgid "Sequence Types"
@@ -3297,13 +3436,15 @@ msgctxt "model:ir.ui.menu,name:menu_model_button_form"
 msgid "Buttons"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_model_data_form"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_model_field_access_form"
 msgid "Fields Access"
-msgstr ""
+msgstr "Leesrecht"
 
 msgctxt "model:ir.ui.menu,name:menu_model_form"
 msgid "Models"
@@ -3325,6 +3466,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Modulen"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Eigenschappen"
@@ -3365,9 +3510,10 @@ msgctxt "model:ir.ui.menu,name:menu_translation_form"
 msgid "Translations"
 msgstr "Vertalingen"
 
+#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_translation_set"
 msgid "Set Translations"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_update"
 msgid "Synchronize Translations"
@@ -3417,9 +3563,10 @@ msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Aanzichten boomstructuurbreedte"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
@@ -3449,9 +3596,10 @@ msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Print form"
 msgstr "Formulier afdrukken"
 
+#, fuzzy
 msgctxt "selection:ir.attachment,type:"
 msgid "Data"
-msgstr ""
+msgstr "Datum"
 
 #, fuzzy
 msgctxt "selection:ir.attachment,type:"
@@ -3488,55 +3636,55 @@ msgstr "Van rechts naar links"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Geïnstalleerd"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Niet geïnstalleerd"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Te installeren"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Te verwijderen"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Bij te werken"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Klaar"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Open"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Geïnstalleerd"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Niet geïnstalleerd"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Te installeren"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Te verwijderen"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Bij te werken"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Onbekend"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3578,9 +3726,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Model"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Verslag"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3643,9 +3792,10 @@ msgctxt "view:ir.action.act_window.domain:"
 msgid "Domain"
 msgstr "Domein"
 
+#, fuzzy
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domains"
-msgstr ""
+msgstr "Domein"
 
 #, fuzzy
 msgctxt "view:ir.action.act_window.view:"
@@ -3728,6 +3878,10 @@ msgid "Action to trigger"
 msgstr "Actie om uit te voeren"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Geplande actie"
 
@@ -3767,17 +3921,19 @@ msgctxt "view:ir.model.button:"
 msgid "Buttons"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "Model gegevens"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.model.field.access:"
 msgid "Field Access"
-msgstr ""
+msgstr "Leesrecht"
 
 #, fuzzy
 msgctxt "view:ir.model.field:"
@@ -3796,9 +3952,10 @@ msgctxt "view:ir.model:"
 msgid "Model Description"
 msgstr "Model omschrijving"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Module configuratie"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
@@ -3806,7 +3963,7 @@ msgstr ""
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "Welkom bij de module configuratie assistent!"
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
@@ -3816,7 +3973,7 @@ msgstr ""
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Conf. assistent items"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
@@ -3824,19 +3981,21 @@ msgstr ""
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Afhankelijkheden"
 
+#, fuzzy
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Afhankelijkheden"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
-msgstr ""
+msgstr "De modules zijn bijgewerkt / geïnstalleerd!"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
@@ -3852,36 +4011,58 @@ msgstr ""
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "Installatie annuleren"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "Verwijderen ongedaan maken"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "Bijwerken annuleren"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "Selecteer voor installatie"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "Selecteer voor verwijderen (beta)"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "Selecteer voor bijwerken"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Module"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Modulen"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Datum"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
 msgstr ""
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Gebruiker"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Eigenschappen"
@@ -3956,9 +4137,10 @@ msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations"
 msgstr "Vertalingen opschonen"
 
+#, fuzzy
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations?"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
 #, fuzzy
 msgctxt "view:ir.translation.clean.succeed:"
@@ -3979,21 +4161,24 @@ msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
 msgstr "Vertaling exporteren"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
+#, fuzzy
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
-msgstr ""
+msgstr "Vertaling synchroniseren"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "Vertalingen opschonen"
 
 #, fuzzy
 msgctxt "view:ir.translation.update.start:"
@@ -4017,9 +4202,10 @@ msgctxt "view:ir.ui.icon:"
 msgid "Icon"
 msgstr "Icoon"
 
+#, fuzzy
 msgctxt "view:ir.ui.icon:"
 msgid "Icons"
-msgstr ""
+msgstr "Icoon"
 
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorite"
@@ -4049,13 +4235,15 @@ msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Aanzichten boomstructuurbreedte"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "Aanzichten boomstructuurbreedte"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
@@ -4074,33 +4262,39 @@ msgctxt "wizard_button:ir.model.print_model_graph,start,print_:"
 msgid "Print"
 msgstr ""
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "Oké"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "Oké"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Annuleren"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
 msgstr ""
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Annuleren"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "Oké"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Annuleren"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
diff --git a/trytond/ir/locale/pt_BR.po b/trytond/ir/locale/pt_BR.po
index 6232e4b..d21c60e 100644
--- a/trytond/ir/locale/pt_BR.po
+++ b/trytond/ir/locale/pt_BR.po
@@ -68,8 +68,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "E-mail inválido na definição do relatório\"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "Os nomes dos anexos devem ser únicos por reurso!"
 
 msgctxt "error:ir.cron:"
@@ -416,6 +417,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Valor do contexto"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Data de criação"
@@ -586,7 +591,7 @@ msgstr "Sequência"
 
 msgctxt "field:ir.action.act_window.view,view:"
 msgid "View"
-msgstr "Exibir"
+msgstr "Sumário"
 
 msgctxt "field:ir.action.act_window.view,write_date:"
 msgid "Write Date"
@@ -1668,6 +1673,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Módulos a atualizar"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Data de criação"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Criado por"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Última modificação"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Último usuário"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Nome"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Recurso"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Data de edição"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Gravado pelo usuário"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Data de criação"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Criado por"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Nome"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Usuário"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Data de edição"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Gravado pelo usuário"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Data de criação"
@@ -2828,6 +2929,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Realizar instalações/atualizações pendentes"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Propriedades"
@@ -2904,6 +3009,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Grafo"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Janela de ato de ação"
@@ -3105,7 +3214,15 @@ msgstr "Atualização / Instalação do módulo terminada"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
-msgstr "Atualização / Instalação do módulo iniciada"
+msgstr "Iniciar a Atualização / Instalação do módulo"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
@@ -3287,6 +3404,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Módulos"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Propriedades"
@@ -3369,7 +3490,7 @@ msgstr "Menu Favoritos"
 
 msgctxt "model:ir.ui.view,name:"
 msgid "View"
-msgstr "Exibir"
+msgstr "Sumário"
 
 msgctxt "model:ir.ui.view.show.start,name:"
 msgid "Show view"
@@ -3539,9 +3660,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Modelo"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Relatório"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3549,7 +3671,7 @@ msgstr "Seleção"
 
 msgctxt "selection:ir.translation,type:"
 msgid "View"
-msgstr "Exibir"
+msgstr "Sumário"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Wizard Button"
@@ -3609,7 +3731,7 @@ msgstr "Domínios"
 
 msgctxt "view:ir.action.act_window.view:"
 msgid "View"
-msgstr "Exibir"
+msgstr "Sumário"
 
 msgctxt "view:ir.action.act_window.view:"
 msgid "Views"
@@ -3684,6 +3806,10 @@ msgid "Action to trigger"
 msgstr "Ação a disparar"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Ação Agendada"
 
@@ -3821,7 +3947,7 @@ msgstr "Cancelar atualização"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr "Cancelar atualização"
+msgstr "Marcar para instalação"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
@@ -3839,6 +3965,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Módulos"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Data"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Usuário"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Propriedades"
@@ -3992,7 +4140,7 @@ msgstr "Mostrar"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
-msgstr "Exibir"
+msgstr "Sumário"
 
 msgctxt "view:ir.ui.view_search:"
 msgid "View Search"
diff --git a/trytond/ir/locale/ru_RU.po b/trytond/ir/locale/ru_RU.po
index 386f613..923dee7 100644
--- a/trytond/ir/locale/ru_RU.po
+++ b/trytond/ir/locale/ru_RU.po
@@ -65,8 +65,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Некорректная эл.почта у отчета \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "Имена вложений должны быть уникальны для ресурса!"
 
 msgctxt "error:ir.cron:"
@@ -152,23 +153,24 @@ msgstr "Модель должна быть уникальной!"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "Зависимости должны быть уникальны у модуля!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "Отсутствует(ют) модуль(и) %s для модуля \"%s\""
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
 msgstr ""
+"От модулей, которые вы пытаетесь удалить, зависят установленные модули:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "Наименование модуля должно быть уникальным"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "Вы не можете удалить модуль, который установлен или будет установлен"
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
@@ -232,11 +234,14 @@ msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
 msgstr "\"На время\" и другие варианты взаимоисключающие"
 
+#, fuzzy
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
 msgstr ""
+"Условие \"%(condition)s\" не является корректным выражением python для "
+"триггера \"%(trigger)s\"."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
@@ -394,6 +399,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Значение контекста"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Дата создания"
@@ -1501,152 +1510,248 @@ msgstr "Уровень"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "Подчиненные"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Дата создания"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Создано пользователем"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Зависимости"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "Наименование"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "Предки"
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Наименование"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "Состояние"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "Версия"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Дата изменения"
 
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Изменено пользователем"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "Действие"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Дата создания"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Создано пользователем"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Наименование"
 
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "Нумерация"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "Состояние"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Дата изменения"
 
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Изменено пользователем"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "Процент"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "Дата создания"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "Создано пользователем"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "Модуль"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "Наименование"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "Наименование"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "Состояние"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "Дата изменения"
 
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "Изменено пользователем"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ID"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "Модули для установки (обновления)"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Дата создания"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Создано пользователем"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Последнее изменение"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Последний пользователь"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Наименование"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Ресурс"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Дата изменения"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Изменено пользователем"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Дата создания"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Создано пользователем"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Наименование"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Пользователь"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Дата изменения"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Изменено пользователем"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Дата создания"
@@ -2287,9 +2392,10 @@ msgctxt "field:ir.ui.menu,action:"
 msgid "Action"
 msgstr "Действие"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu,action_keywords:"
 msgid "Action Keywords"
-msgstr ""
+msgstr "Действие ключевых слов"
 
 msgctxt "field:ir.ui.menu,active:"
 msgid "Active"
@@ -2691,11 +2797,14 @@ msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
 msgstr "Это правило выполняется, если по крайней мере одно правило истинно"
 
+#, fuzzy
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"Выражение Python вычисляется для записи \"self\".\n"
+"Оно запускает действие при значении \"True\"."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
@@ -2812,6 +2921,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Установить / Обновить"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Свойства"
@@ -2888,6 +3001,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Графика"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Действие окна"
@@ -3003,9 +3120,10 @@ msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
 msgstr "Французкий"
 
+#, fuzzy
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "Болгарский"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
@@ -3061,34 +3179,43 @@ msgstr "Распечатать граф модели"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "Модуль"
 
+#, fuzzy
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "Мастер конфигурации модуля"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "Мастер конфигурации модуля"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "Запустить мастер конфигурации после установки модуля"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "Мастер конфигурации модуля"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "Зависимости"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "Установка (обновление) модуля завершено"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "Начать установку (обновление) модуля"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
@@ -3272,6 +3399,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Модули"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Свойства"
@@ -3364,9 +3495,10 @@ msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
 msgstr "Просмотр поиска"
 
+#, fuzzy
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Ширина вида список"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
@@ -3434,55 +3566,55 @@ msgstr "Справа на лево"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Установлен"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Не установлен"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Для установки"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Для удаления"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Для обновления"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "Выполнено"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "Открыть"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "Установлен"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "Не установлен"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "Для установки"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "Для удаления"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "Для обновления"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "Неизвестно"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
@@ -3524,9 +3656,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Модель"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Отчет"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3661,15 +3794,20 @@ msgctxt "view:ir.attachment:"
 msgid "Attachments"
 msgstr "Вложения"
 
+#, fuzzy
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "Последнее изменение"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
 msgstr "Действие триггера"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Запланированное действие"
 
@@ -3709,9 +3847,10 @@ msgctxt "view:ir.model.button:"
 msgid "Buttons"
 msgstr "Кнопки"
 
+#, fuzzy
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "Данные модели"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
@@ -3737,9 +3876,10 @@ msgctxt "view:ir.model:"
 msgid "Model Description"
 msgstr "Описание модели"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "Конфигурация модуля"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
@@ -3747,82 +3887,106 @@ msgstr ""
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "Добро пожаловать в мастер конфигурации модуля!"
 
+#, fuzzy
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
 msgstr ""
+"Вы сможете настроить базу данных в зависимости от установленных модулей."
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "Мастер конфигурации"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
-msgstr ""
+msgstr "Следующий шаг Мастера конфигурации!"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "Зависимости"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "Зависимость"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
-msgstr ""
+msgstr "Обновление системы выполнено"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
-msgstr ""
+msgstr "Модули были установлены (обновлены)!"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
-msgstr ""
+msgstr "Эта операция может занять несколько минут."
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "System Upgrade"
-msgstr ""
+msgstr "Обновление системы"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Your system will be upgraded."
-msgstr ""
+msgstr "База данных будет обновлена."
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "Отменить установку"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "Отмена удаления"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "Отмена обновления"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "Установить"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "Удалить (бета)"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "Обновить"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "Модуль"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "Модули"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Дата"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Пользователь"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Свойства"
@@ -3972,9 +4136,10 @@ msgctxt "view:ir.ui.menu:"
 msgid "Menu"
 msgstr "Меню"
 
+#, fuzzy
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr ""
+msgstr "Просмотр"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
@@ -3988,13 +4153,15 @@ msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
 msgstr "Просмотры поиска"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "Ширина вида список"
 
+#, fuzzy
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "Ширина вида список"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
@@ -4012,37 +4179,40 @@ msgctxt "wizard_button:ir.model.print_model_graph,start,print_:"
 msgid "Print"
 msgstr "Печать"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "Ок"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "Ок"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отменить"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "Далее"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отменить"
 
+#, fuzzy
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "Ок"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "Отменить"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "Начать установку (обновление)"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
diff --git a/trytond/ir/locale/sl_SI.po b/trytond/ir/locale/sl_SI.po
index c76857d..0abc790 100644
--- a/trytond/ir/locale/sl_SI.po
+++ b/trytond/ir/locale/sl_SI.po
@@ -4,14 +4,6 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
 
 msgctxt "error:access_error:"
 msgid ""
-"You try to bypass an access rule!\n"
-"(Document type: %s)"
-msgstr ""
-"Poskušate zaobiti pravilo dostopa.\n"
-"(Vrsta dokumenta: %s"
-
-msgctxt "error:access_error:"
-msgid ""
 "You try to bypass an access rule.\n"
 "(Document type: %s)"
 msgstr ""
@@ -78,8 +70,9 @@ msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
 msgstr "Neveljavna definicija epošte na izpisu \"%s\"."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
+msgid "The names of attachments must be unique by resource."
 msgstr "Imena priponk morajo biti unikatna med resursi."
 
 msgctxt "error:ir.cron:"
@@ -270,14 +263,6 @@ msgstr "Neveljaven XML za pogled \"%s\"."
 
 msgctxt "error:read_error:"
 msgid ""
-"You try to read records that don't exist anymore!\n"
-"(Document type: %s)"
-msgstr ""
-"Poskušate brati zapise, ki ne obstajajo več.\n"
-"(Vrsta dokumenta: %s)"
-
-msgctxt "error:read_error:"
-msgid ""
 "You try to read records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
@@ -338,14 +323,6 @@ msgstr "Najdenih je preveč vez: %r v %s"
 
 msgctxt "error:write_error:"
 msgid ""
-"You try to write on records that don't exist anymore!\n"
-"(Document type: %s)"
-msgstr ""
-"Poskušate zapisati zapise, ki ne obstajajo več.\n"
-"(Vrsta dokumenta: %s)"
-
-msgctxt "error:write_error:"
-msgid ""
 "You try to write on records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
@@ -436,6 +413,10 @@ msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
 msgstr "Vrednost konteksta"
 
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
+
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
 msgstr "Izdelano"
@@ -1688,6 +1669,102 @@ msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
 msgstr "Moduli za posodobitev"
 
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "Izdelano"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "Izdelal"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "ID"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "Zadnja sprememba"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "Zadnji uporabnik"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
+msgstr ""
+
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "Naziv"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "Vir"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "Zapisano"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "Zapisal"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
+msgid "Create Date"
+msgstr "Izdelano"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "Izdelal"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "ID"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "Naziv"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "Uporabnik"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "Zapisano"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "Zapisal"
+
 msgctxt "field:ir.property,create_date:"
 msgid "Create Date"
 msgstr "Izdelano"
@@ -2846,6 +2923,10 @@ msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
 msgstr "Namesti/nadgradi"
 
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
 msgstr "Lastnosti"
@@ -2922,6 +3003,10 @@ msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
 msgstr "Diagram"
 
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
+
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
 msgstr "Ukrep za okna"
@@ -3124,6 +3209,14 @@ msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
 msgstr "Začetek nadgradnje modula"
 
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
+msgstr ""
+
 msgctxt "model:ir.property,name:"
 msgid "Property"
 msgstr "Lastnost"
@@ -3304,6 +3397,10 @@ msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
 msgstr "Moduli"
 
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
 msgstr "Lastnosti"
@@ -3465,10 +3562,6 @@ msgid "Right-to-left"
 msgstr "Z desne proti levi"
 
 msgctxt "selection:ir.module,state:"
-msgid ""
-msgstr ""
-
-msgctxt "selection:ir.module,state:"
 msgid "Installed"
 msgstr "Nameščeno"
 
@@ -3476,6 +3569,11 @@ msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
 msgstr "Ni nameščeno"
 
+#, fuzzy
+msgctxt "selection:ir.module,state:"
+msgid "To be installed"
+msgstr "Za namestiti"
+
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
 msgstr "Za odstraniti"
@@ -3556,9 +3654,10 @@ msgctxt "selection:ir.translation,type:"
 msgid "Model"
 msgstr "Model"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "Poročilo"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
@@ -3701,6 +3800,10 @@ msgid "Action to trigger"
 msgstr "Sprožitev ukrepa"
 
 msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
+
+msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
 msgstr "Načrtovan ukrep"
 
@@ -3854,6 +3957,28 @@ msgctxt "view:ir.module:"
 msgid "Modules"
 msgstr "Moduli"
 
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "Datum"
+
+msgctxt "view:ir.note:"
+msgid "Note"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "Uporabnik"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
 msgstr "Lastnosti"
diff --git a/trytond/ir/locale/nl_NL.po b/trytond/ir/locale/zh_CN.po
similarity index 72%
copy from trytond/ir/locale/nl_NL.po
copy to trytond/ir/locale/zh_CN.po
index 669c007..d9f5739 100644
--- a/trytond/ir/locale/nl_NL.po
+++ b/trytond/ir/locale/zh_CN.po
@@ -7,64 +7,67 @@ msgid ""
 "You try to bypass an access rule.\n"
 "(Document type: %s)"
 msgstr ""
+"试图绕过操作权限规则.\n"
+"(文档类型: %s)"
 
 msgctxt "error:delete_xml_record:"
 msgid "You are not allowed to delete this record."
-msgstr "Het is u niet toegestaan dit item te verwijderen."
+msgstr "不允许删除此条记录"
 
 msgctxt "error:digits_validation_record:"
 msgid ""
 "The number of digits \"%(digits)s\" of field \"%(field)s\" on \"%(value)s\" "
 "exceeds its limit."
-msgstr ""
+msgstr " 数据\"%(field)s\"的值\"%(value)s\" 的位数\"%(digits)s\"超过限制."
 
 msgctxt "error:domain_validation_record:"
 msgid ""
 "The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
 " to its domain."
-msgstr ""
+msgstr "域设置下模型\"%(model)s\" 的数据 \"%(field)s\"无效."
 
 msgctxt "error:foreign_model_exist:"
 msgid ""
 "Could not delete the records because they are used on field \"%(field)s\" of"
 " \"%(model)s\"."
-msgstr ""
+msgstr "模型\"%(model)s\"的数据 \"%(field)s\" 正在使用,无法删除项目."
 
 msgctxt "error:foreign_model_missing:"
 msgid "The value \"%(value)s\" of field \"%(field)s\" on \"%(model)s\" doesn't exist."
-msgstr ""
+msgstr "模型\"%(model)s\"的数据 \"%(field)s\" 的值\"%(value)s\" 不存在."
 
 msgctxt "error:ir.action.act_window.domain:"
 msgid "Invalid domain or search criteria \"%(domain)s\" on action \"%(action)s\"."
-msgstr ""
+msgstr "动作\"%(action)s\"的域配置或查找表达式\"%(domain)s\"无效."
 
 msgctxt "error:ir.action.act_window:"
 msgid "Invalid context \"%(context)s\" on action \"%(action)s\"."
-msgstr ""
+msgstr "动作\"%(action)s\"的条件\"%(context)s\"设置无效."
 
 msgctxt "error:ir.action.act_window:"
 msgid "Invalid domain or search criteria \"%(domain)s\" on action \"%(action)s\"."
-msgstr ""
+msgstr "动作\"%(action)s\"的域配置或查找表达式\"%(domain)s\"无效."
 
 msgctxt "error:ir.action.act_window:"
 msgid "Invalid view \"%(view)s\" for action \"%(action)s\"."
-msgstr ""
+msgstr "动作\"%(action)s\"的视图\"%(view)s\"无效."
 
 msgctxt "error:ir.action.keyword:"
 msgid "Wrong wizard model in keyword action \"%s\"."
-msgstr ""
+msgstr "关键字操作\"%s\"的向导模型有误."
 
 msgctxt "error:ir.action.report:"
 msgid "Invalid email definition on report \"%s\"."
-msgstr ""
+msgstr "报表\"%s\"的email定义无效."
 
+#, fuzzy
 msgctxt "error:ir.attachment:"
-msgid "The  names of attachments must be unique by resource!"
-msgstr "De namen van de bijlagen moeten uniek zijn per bron!"
+msgid "The names of attachments must be unique by resource."
+msgstr "附件文档名必须唯一 !"
 
 msgctxt "error:ir.cron:"
 msgid "Scheduled action failed"
-msgstr "Geplande actie mislukt"
+msgstr "计划动作失败"
 
 msgctxt "error:ir.cron:"
 msgid ""
@@ -74,3525 +77,3574 @@ msgid ""
 "\n"
 "%s\n"
 msgstr ""
+"下列动作没有执行: \"%s\"\n"
+"%s\n"
+"Traceback: \n"
+"\n"
+"%s\n"
 
 msgctxt "error:ir.lang:"
 msgid "Default language can not be deleted."
-msgstr ""
+msgstr "默认语言不可删除."
 
 msgctxt "error:ir.lang:"
 msgid "Invalid date format \"%(format)s\" on \"%(language)s\" language."
-msgstr ""
+msgstr "语言\"%(language)s\"中的日期格式 \"%(format)s\"设置无效."
 
 msgctxt "error:ir.lang:"
 msgid "Invalid grouping \"%(grouping)s\" on \"%(language)s\" language."
-msgstr ""
+msgstr "语言\"%(language)s\"中的分组 \"%(grouping)s\"设置无效."
 
 msgctxt "error:ir.lang:"
 msgid "The default language must be translatable."
-msgstr ""
+msgstr "默认语言应设置为可翻译成其他语言."
 
 msgctxt "error:ir.lang:"
 msgid "decimal_point and thousands_sep must be different!"
-msgstr "Decimaal teken en duizendtal teken moet verschillend zijn!"
+msgstr "小数点和千位分隔符不能相同!"
 
 msgctxt "error:ir.model.access:"
 msgid "You can not create this kind of document! (%s)"
-msgstr "U kunt dit type document niet aanmaken! (%s)"
+msgstr "(%s) 类型文档无创建权限!"
 
 msgctxt "error:ir.model.access:"
 msgid "You can not delete this document! (%s)"
-msgstr "U kunt dit document niet verwijderen! (%s)"
+msgstr "文件 (%s) 无删除权限!"
 
 msgctxt "error:ir.model.access:"
 msgid "You can not read this document! (%s)"
-msgstr "U kunt dit document openen! (%s)"
+msgstr "文件 (%s) 无读取权限!"
 
 msgctxt "error:ir.model.access:"
 msgid "You can not write in this document! (%s)"
-msgstr "U kunt dit document niet muteren! (%s)"
+msgstr "文件 (%s) 无写入权限!"
 
 msgctxt "error:ir.model.button:"
 msgid "The button name in model must be unique!"
-msgstr ""
+msgstr "模型中按钮的名称必须唯一!"
 
 msgctxt "error:ir.model.data:"
 msgid "The triple (fs_id, module, model) must be unique!"
-msgstr "Het drietal (fs_id, module, model) moet uniek zijn!"
+msgstr " (fs_id, module, model) 组合必须唯一!"
 
 msgctxt "error:ir.model.field.access:"
 msgid "You can not read the field! (%s.%s)"
-msgstr ""
+msgstr "数据 (%s.%s)  无读取权限 !"
 
 msgctxt "error:ir.model.field.access:"
 msgid "You can not write on the field! (%s.%s)"
-msgstr ""
+msgstr "数据 (%s.%s)  无写入权限 !"
 
 msgctxt "error:ir.model.field:"
 msgid "Model Field name \"%s\" is not a valid python identifier."
-msgstr ""
+msgstr "模型数据值 \"%s\" 不是合法的python identifier."
 
 msgctxt "error:ir.model.field:"
 msgid "The field name in model must be unique!"
-msgstr "De veldnaam in het model moet uniek zijn!"
+msgstr "模型的数据名称必须唯一!"
 
 msgctxt "error:ir.model:"
 msgid "Module name \"%s\" is not a valid python identifier."
-msgstr ""
+msgstr "模块名 \"%s\" 不是合法的python identifier."
 
 msgctxt "error:ir.model:"
 msgid "The model must be unique!"
-msgstr "Het model moet uniek zijn!"
+msgstr "模型必须唯一!"
 
 msgctxt "error:ir.module.dependency:"
 msgid "Dependency must be unique by module!"
-msgstr ""
+msgstr "模块的依赖对象必须唯一!"
 
 msgctxt "error:ir.module:"
 msgid "Missing dependencies %s for module \"%s\""
-msgstr ""
+msgstr "模块\"%s\"的依赖 %s缺失"
 
 msgctxt "error:ir.module:"
 msgid "The modules you are trying to uninstall depends on installed modules:"
-msgstr ""
+msgstr "卸载模块同已安装模块的依赖关系:"
 
 msgctxt "error:ir.module:"
 msgid "The name of the module must be unique!"
-msgstr ""
+msgstr "模块名称必须唯一!"
 
 msgctxt "error:ir.module:"
 msgid "You can not remove a module that is installed or will be installed"
-msgstr ""
+msgstr "无法移除未安装或者待装状态的模块"
 
 msgctxt "error:ir.rule.group:"
 msgid "Global and Default are mutually exclusive!"
-msgstr "Globaal en standaard sluiten elkaar uit!"
+msgstr "全局和默认是互斥的关系!"
 
 msgctxt "error:ir.rule:"
 msgid "Invalid domain in rule \"%s\"."
-msgstr ""
+msgstr "规则\"%s\"的域配置无效."
 
 msgctxt "error:ir.sequence.strict:"
 msgid "Invalid prefix \"%(prefix)s\" on sequence \"%(sequence)s\"."
-msgstr ""
+msgstr "序列 \"%(sequence)s\"前缀\"%(prefix)s\"无效."
 
 msgctxt "error:ir.sequence.strict:"
 msgid "Invalid suffix \"%(suffix)s\" on sequence \"%(sequence)s\"."
-msgstr ""
+msgstr "序列 \"%(sequence)s\"后缀\"%(suffix)s\"无效."
 
 msgctxt "error:ir.sequence.strict:"
 msgid "Last Timestamp cannot be in the future on sequence \"%s\"."
-msgstr ""
+msgstr "上一时间戳不可用在序列\"%s\"将来态."
 
 msgctxt "error:ir.sequence.strict:"
 msgid "Missing sequence."
-msgstr ""
+msgstr "序列缺失."
 
 msgctxt "error:ir.sequence.strict:"
 msgid "Timestamp rounding should be greater than 0"
-msgstr ""
+msgstr "时间戳的近似整数应大于0"
 
 msgctxt "error:ir.sequence:"
 msgid "Invalid prefix \"%(prefix)s\" on sequence \"%(sequence)s\"."
-msgstr ""
+msgstr "序列 \"%(sequence)s\"前缀\"%(prefix)s\"无效."
 
 msgctxt "error:ir.sequence:"
 msgid "Invalid suffix \"%(suffix)s\" on sequence \"%(sequence)s\"."
-msgstr ""
+msgstr "序列 \"%(sequence)s\"后缀\"%(suffix)s\"无效."
 
 msgctxt "error:ir.sequence:"
 msgid "Last Timestamp cannot be in the future on sequence \"%s\"."
-msgstr ""
+msgstr "上一时间戳不可用在序列\"%s\"将来态."
 
 msgctxt "error:ir.sequence:"
 msgid "Missing sequence."
-msgstr ""
+msgstr "序列缺失."
 
 msgctxt "error:ir.sequence:"
 msgid "Timestamp rounding should be greater than 0"
-msgstr ""
+msgstr "时间戳的近似整数应大于0"
 
 msgctxt "error:ir.translation:"
 msgid "Translation must be unique"
-msgstr "Vertaling moet uniek zijn!"
+msgstr "翻译字符串必须唯一!"
 
 msgctxt "error:ir.translation:"
 msgid ""
 "You can not export translation %(name)s because it is an overridden "
 "translation by module %(overriding_module)s"
-msgstr ""
+msgstr "翻译%(name)s源于模块%(overriding_module)s的条目替换,无法导出."
 
 msgctxt "error:ir.trigger:"
 msgid "\"On Time\" and others are mutually exclusive!"
-msgstr "\"Op tijd\" en anderen sluiten elkaar uit!"
+msgstr "“On Time\"和其他触发器互不相容."
 
 msgctxt "error:ir.trigger:"
 msgid ""
 "Condition \"%(condition)s\" is not a valid PYSON expression on trigger "
 "\"%(trigger)s\"."
-msgstr ""
+msgstr "触发器\"%(trigger)s\"的条件\"%(condition)s\"配置不是合法的PYSON表达式."
 
 msgctxt "error:ir.ui.menu:"
 msgid "\"%s\" is not a valid menu name because it is not allowed to contain \" / \"."
-msgstr ""
+msgstr "\"%s\"含有\" / \",不可作为菜单名称."
 
 msgctxt "error:ir.ui.view:"
 msgid "Invalid XML for view \"%s\"."
-msgstr ""
+msgstr "视图\"%s\"的XML表达不合法."
 
 msgctxt "error:read_error:"
 msgid ""
 "You try to read records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"试图读取不存在的项目.\n"
+"(文件类型: %s)"
 
 msgctxt "error:recursion_error:"
 msgid ""
 "Recursion error: Record \"%(rec_name)s\" with parent \"%(parent_rec_name)s\""
 " was configured as ancestor of itself."
-msgstr ""
+msgstr "递归错误:数据 \"%(rec_name)s不可同时为\"%(parent_rec_name)s\"的父级和子级."
 
 msgctxt "error:reference_syntax_error:"
 msgid "Syntax error for reference %r in %s"
-msgstr "Foutieve verwijzing voor %r in %s"
+msgstr "reference %r in %s 语法错误"
 
 msgctxt "error:relation_not_found:"
 msgid "Relation not found: %r in %s"
-msgstr "Relatie niet gevonden: %r in %s"
+msgstr "不是包含关系: %r in %s"
 
 msgctxt "error:required_field:"
 msgid "The field \"%(field)s\" on \"%(model)s\" is required."
-msgstr ""
+msgstr "模型 \"%(model)s\" 的 \"%(field)s\"为必填数据."
 
 msgctxt "error:required_validation_record:"
 msgid "The field \"%(field)s\" on \"%(model)s\" is required."
-msgstr ""
+msgstr "模型 \"%(model)s\" 的 \"%(field)s\"为必填数据."
 
 msgctxt "error:search_function_missing:"
 msgid "Missing search function on field \"%s\"."
-msgstr "Zoekfunctie ontbreekt voor veld \" %s\"."
+msgstr "数据 \"%s\" 缺少搜索方法."
 
 msgctxt "error:selection_validation_record:"
 msgid ""
 "The value \"%(value)s\" of field \"%(field)s\" on \"%(model)s\" is not in "
 "the selection."
-msgstr ""
+msgstr "此段不含模型\"%(model)s\"的数据\"%(field)s\"的值\"%(value)s\" ."
 
 msgctxt "error:selection_value_notfound:"
 msgid "Value not in the selection for field \"%s\"."
-msgstr ""
+msgstr "此段含数据 \"%s\"的值."
 
 msgctxt "error:size_validation_record:"
 msgid "The size \"%(size)s\" of the field \"%(field)s\" on \"%(model)s\" is too long."
-msgstr ""
+msgstr "模型\"%(model)s\"的数据 \"%(field)s\"的大小\"%(size)s\"位数太长."
 
 msgctxt "error:time_format_validation_record:"
 msgid "The time value \"%(value)s\" of field \"%(field)s\" on \"%(model)s\" is not valid."
-msgstr ""
+msgstr "模型\"%(model)s\"的数据 \"%(field)s\" 的时间值\"%(value)s\" 不存在."
 
 msgctxt "error:too_many_relations_found:"
 msgid "Too many relations found: %r in %s"
-msgstr "Te veel relaties gevonden: %r in %s"
+msgstr "关联太多: %r in %s"
 
 msgctxt "error:write_error:"
 msgid ""
 "You try to write on records that don't exist anymore.\n"
 "(Document type: %s)"
 msgstr ""
+"试图写入不存在的项目.\n"
+"(文件类型: %s)"
 
 msgctxt "error:write_xml_record:"
 msgid "You are not allowed to modify this record."
-msgstr "Het is u niet toegestaan dit item te muteren."
+msgstr "不允许修改此条记录."
 
 msgctxt "error:xml_id_syntax_error:"
 msgid "Syntax error for XML id %r in %s"
-msgstr "Foutieve verwijzing voor XML id %r in %s"
+msgstr " XML id %r in %s 语法错误"
 
 msgctxt "error:xml_record_desc:"
 msgid "This record is part of the base configuration."
-msgstr "Dit item is onderdeel van de basis configuratie."
+msgstr "此项是基本设置."
 
 msgctxt "field:ir.action,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期:"
 
 msgctxt "field:ir.action,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.action,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "field:ir.action,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.action,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.action,keywords:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
 msgctxt "field:ir.action,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.action,usage:"
 msgid "Usage"
-msgstr "Gebruik"
+msgstr "用法"
 
 msgctxt "field:ir.action,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.act_window,act_window_domains:"
 msgid "Domains"
-msgstr ""
+msgstr "域配置"
 
 msgctxt "field:ir.action.act_window,act_window_views:"
 msgid "Views"
-msgstr "Aanzichten"
+msgstr "视图"
 
 msgctxt "field:ir.action.act_window,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "操作"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.act_window,context:"
 msgid "Context Value"
-msgstr "Samenhang waarde"
+msgstr "场景值"
+
+msgctxt "field:ir.action.act_window,context_model:"
+msgid "Context Model"
+msgstr ""
 
 msgctxt "field:ir.action.act_window,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期:"
 
 msgctxt "field:ir.action.act_window,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.action.act_window,domain:"
 msgid "Domain Value"
-msgstr "Domein waarde"
+msgstr "域配置"
 
 msgctxt "field:ir.action.act_window,domains:"
 msgid "Domains"
-msgstr ""
+msgstr "域配置"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.action.act_window,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,keywords:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
 msgctxt "field:ir.action.act_window,limit:"
 msgid "Limit"
-msgstr "Begrenzing"
+msgstr "限制"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.action.act_window,order:"
 msgid "Order Value"
-msgstr ""
+msgstr "顺序"
 
 msgctxt "field:ir.action.act_window,pyson_context:"
 msgid "PySON Context"
-msgstr "PySON verband"
+msgstr "PYSON 场景"
 
 msgctxt "field:ir.action.act_window,pyson_domain:"
 msgid "PySON Domain"
-msgstr "PySON domein"
+msgstr "PYSON 域"
 
 msgctxt "field:ir.action.act_window,pyson_order:"
 msgid "PySON Order"
-msgstr ""
+msgstr "PySON 顺序"
 
 msgctxt "field:ir.action.act_window,pyson_search_value:"
 msgid "PySON Search Criteria"
-msgstr "PySON zoekargument"
+msgstr "PySON查找表达式"
 
 msgctxt "field:ir.action.act_window,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action.act_window,res_model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.action.act_window,search_value:"
 msgid "Search Criteria"
-msgstr "Zoekargumenten"
+msgstr "查找表达式"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window,usage:"
 msgid "Usage"
-msgstr "Gebruik"
+msgstr "用法"
 
 msgctxt "field:ir.action.act_window,views:"
 msgid "Views"
-msgstr "Aanzichten"
+msgstr "视图"
 
 msgctxt "field:ir.action.act_window,window_name:"
 msgid "Window Name"
-msgstr "Aanzicht naam"
+msgstr "窗口"
 
 msgctxt "field:ir.action.act_window,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.act_window,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,act_window:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.act_window.domain,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期:"
 
 msgctxt "field:ir.action.act_window.domain,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "field:ir.action.act_window.domain,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.domain,sequence:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
 msgctxt "field:ir.action.act_window.domain,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.act_window.domain,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.act_window.view,act_window:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
-#, fuzzy
 msgctxt "field:ir.action.act_window.view,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.act_window.view,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期:"
 
 msgctxt "field:ir.action.act_window.view,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.action.act_window.view,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.action.act_window.view,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action.act_window.view,sequence:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
 msgctxt "field:ir.action.act_window.view,view:"
 msgid "View"
-msgstr "Overzicht"
+msgstr "视图"
 
 msgctxt "field:ir.action.act_window.view,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.act_window.view,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.keyword,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
 msgctxt "field:ir.action.keyword,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.action.keyword,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.action.keyword,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:ir.action.keyword,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.action.keyword,keyword:"
 msgid "Keyword"
-msgstr "Trefwoord"
+msgstr "关键词"
 
 msgctxt "field:ir.action.keyword,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.action.keyword,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action.keyword,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.keyword,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.report,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
-#, fuzzy
 msgctxt "field:ir.action.report,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.report,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.action.report,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.action.report,direct_print:"
 msgid "Direct Print"
-msgstr "Direct afdrukken"
+msgstr "直接打印"
 
 msgctxt "field:ir.action.report,email:"
 msgid "Email"
-msgstr "E-mail"
+msgstr "电子邮箱"
 
 msgctxt "field:ir.action.report,extension:"
 msgid "Extension"
-msgstr "Uitbreiding"
+msgstr "扩展"
 
-#, fuzzy
 msgctxt "field:ir.action.report,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "field:ir.action.report,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.action.report,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action.report,keywords:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
 msgctxt "field:ir.action.report,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.action.report,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
-#, fuzzy
 msgctxt "field:ir.action.report,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.action.report,pyson_email:"
 msgid "PySON Email"
-msgstr ""
+msgstr "PySON 邮箱"
 
 msgctxt "field:ir.action.report,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.action.report,report:"
 msgid "Path"
-msgstr "Pad"
+msgstr "路径"
 
 msgctxt "field:ir.action.report,report_content:"
 msgid "Content"
-msgstr "Inhoud"
+msgstr "内容"
 
-#, fuzzy
 msgctxt "field:ir.action.report,report_content_custom:"
 msgid "Content"
-msgstr "Inhoud"
+msgstr "内容"
 
 msgctxt "field:ir.action.report,report_content_name:"
 msgid "Content Name"
-msgstr ""
+msgstr "内容标识"
 
 msgctxt "field:ir.action.report,report_name:"
 msgid "Internal Name"
-msgstr "Interne naam"
+msgstr "内部标识"
 
 msgctxt "field:ir.action.report,template_extension:"
 msgid "Template Extension"
-msgstr ""
+msgstr "模版扩展"
 
-#, fuzzy
 msgctxt "field:ir.action.report,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
-#, fuzzy
 msgctxt "field:ir.action.report,usage:"
 msgid "Usage"
-msgstr "Gebruik"
+msgstr "用法"
 
 msgctxt "field:ir.action.report,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.report,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.url,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
-#, fuzzy
 msgctxt "field:ir.action.url,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.url,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.action.url,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.action.url,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "field:ir.action.url,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.action.url,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action.url,keywords:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
-#, fuzzy
 msgctxt "field:ir.action.url,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.action.url,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.action.url,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.action.url,url:"
 msgid "Action Url"
-msgstr "Actie URL"
+msgstr "动作 Url"
 
-#, fuzzy
 msgctxt "field:ir.action.url,usage:"
 msgid "Usage"
-msgstr "Gebruik"
+msgstr "用法"
 
 msgctxt "field:ir.action.url,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.url,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.action.wizard,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.action.wizard,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.action.wizard,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.action.wizard,email:"
 msgid "Email"
-msgstr "E-mail"
+msgstr "电子邮箱"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.action.wizard,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,keywords:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
 msgctxt "field:ir.action.wizard,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.action.wizard,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
-#, fuzzy
 msgctxt "field:ir.action.wizard,usage:"
 msgid "Usage"
-msgstr "Gebruik"
+msgstr "用法"
 
 msgctxt "field:ir.action.wizard,window:"
 msgid "Window"
-msgstr "Scherm"
+msgstr "窗口"
 
 msgctxt "field:ir.action.wizard,wiz_name:"
 msgid "Wizard name"
-msgstr "Assistent naam"
+msgstr "向导名称"
 
 msgctxt "field:ir.action.wizard,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action.wizard,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.attachment,collision:"
 msgid "Collision"
-msgstr "Botsing"
+msgstr "冲突"
 
 msgctxt "field:ir.attachment,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.attachment,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.attachment,data:"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
 msgctxt "field:ir.attachment,data_size:"
 msgid "Data size"
-msgstr ""
+msgstr "大小"
 
 msgctxt "field:ir.attachment,description:"
 msgid "Description"
-msgstr "Omschrijving"
+msgstr "描述"
 
 msgctxt "field:ir.attachment,digest:"
 msgid "Digest"
-msgstr "Verwerken"
+msgstr "吸收"
 
 msgctxt "field:ir.attachment,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.attachment,last_modification:"
 msgid "Last Modification"
-msgstr ""
+msgstr "最近更改"
 
 msgctxt "field:ir.attachment,last_user:"
 msgid "Last User"
-msgstr ""
+msgstr "最近用户"
 
 msgctxt "field:ir.attachment,link:"
 msgid "Link"
-msgstr "Verbinding"
+msgstr "链接"
 
-#, fuzzy
 msgctxt "field:ir.attachment,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.attachment,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.attachment,resource:"
 msgid "Resource"
-msgstr "Middel"
+msgstr "附件文档资源"
 
 msgctxt "field:ir.attachment,summary:"
 msgid "Summary"
-msgstr ""
+msgstr "摘要"
 
-#, fuzzy
 msgctxt "field:ir.attachment,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.attachment,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.attachment,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.cache,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.cache,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.cache,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.cache,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.cache,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.cache,timestamp:"
 msgid "Timestamp"
-msgstr "Tijdmarkering"
+msgstr "时间戳"
 
 msgctxt "field:ir.cache,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.cache,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.configuration,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.configuration,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.configuration,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.configuration,language:"
 msgid "language"
-msgstr ""
+msgstr "语言"
 
-#, fuzzy
 msgctxt "field:ir.configuration,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.configuration,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.configuration,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.cron,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.cron,args:"
 msgid "Arguments"
-msgstr "Argumenten"
+msgstr "参数"
 
 msgctxt "field:ir.cron,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.cron,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.cron,function:"
 msgid "Function"
-msgstr "Functie"
+msgstr "方法"
 
 msgctxt "field:ir.cron,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.cron,interval_number:"
 msgid "Interval Number"
-msgstr "Interval nummer"
+msgstr "间隔"
 
 msgctxt "field:ir.cron,interval_type:"
 msgid "Interval Unit"
-msgstr "Interval eenheid"
+msgstr "单位"
 
 msgctxt "field:ir.cron,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.cron,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.cron,next_call:"
 msgid "Next Call"
-msgstr ""
+msgstr "下次调用"
 
 msgctxt "field:ir.cron,number_calls:"
 msgid "Number of Calls"
-msgstr ""
+msgstr "调用次数"
 
 msgctxt "field:ir.cron,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.cron,repeat_missed:"
 msgid "Repeat Missed"
-msgstr ""
+msgstr "重启错过项目"
 
 msgctxt "field:ir.cron,request_user:"
 msgid "Request User"
-msgstr "Verzoek gebruiker"
+msgstr "请求用户"
 
 msgctxt "field:ir.cron,user:"
 msgid "Execution User"
-msgstr "Uitvoerende gebruiker"
+msgstr "执行用户"
 
 msgctxt "field:ir.cron,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.cron,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.date,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.export,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.export,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.export,export_fields:"
 msgid "Fields"
-msgstr "Velden"
+msgstr "数据"
 
 msgctxt "field:ir.export,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.export,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.export,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.export,resource:"
 msgid "Resource"
-msgstr "Middel"
+msgstr "资源"
 
 msgctxt "field:ir.export,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.export,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.export.line,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.export.line,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.export.line,export:"
 msgid "Export"
-msgstr "Exporteren"
+msgstr "导出"
 
 msgctxt "field:ir.export.line,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.export.line,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.export.line,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.export.line,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.export.line,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.lang,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.lang,code:"
 msgid "Code"
-msgstr "Code"
+msgstr "语言编码"
 
 msgctxt "field:ir.lang,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.lang,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.lang,date:"
 msgid "Date"
-msgstr "Datum"
+msgstr "日期格式"
 
 msgctxt "field:ir.lang,decimal_point:"
 msgid "Decimal Separator"
-msgstr "Decimaalteken"
+msgstr "小数点"
 
 msgctxt "field:ir.lang,direction:"
 msgid "Direction"
-msgstr "Richting"
+msgstr "语言方向"
 
 msgctxt "field:ir.lang,grouping:"
 msgid "Grouping"
-msgstr "Groeperen"
+msgstr "类别"
 
 msgctxt "field:ir.lang,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.lang,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.lang,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.lang,thousands_sep:"
 msgid "Thousands Separator"
-msgstr "Duizendtal teken"
+msgstr "千位分隔符"
 
 msgctxt "field:ir.lang,translatable:"
 msgid "Translatable"
-msgstr "Vertaalbaar"
+msgstr "可翻译"
 
 msgctxt "field:ir.lang,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.lang,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.model,fields:"
 msgid "Fields"
-msgstr "Velden"
+msgstr "数据"
 
 msgctxt "field:ir.model,global_search_p:"
 msgid "Global Search"
-msgstr ""
+msgstr "全局查找"
 
 msgctxt "field:ir.model,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.model,info:"
 msgid "Information"
-msgstr "Informatie"
+msgstr "信息"
 
 msgctxt "field:ir.model,model:"
 msgid "Model Name"
-msgstr "Naam module"
+msgstr "模型名称"
 
 msgctxt "field:ir.model,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
 msgctxt "field:ir.model,name:"
 msgid "Model Description"
-msgstr "Model omschrijving"
+msgstr "模型描述"
 
 msgctxt "field:ir.model,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.model,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.access,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.access,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.model.access,description:"
 msgid "Description"
-msgstr "Omschrijving"
+msgstr "描述"
 
 msgctxt "field:ir.model.access,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.model.access,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.model.access,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.model.access,perm_create:"
 msgid "Create Access"
-msgstr "Mag aanmaken"
+msgstr "新建"
 
 msgctxt "field:ir.model.access,perm_delete:"
 msgid "Delete Access"
-msgstr "Toegang verwijderen"
+msgstr "删除"
 
 msgctxt "field:ir.model.access,perm_read:"
 msgid "Read Access"
-msgstr "Leesrecht"
+msgstr "读取"
 
 msgctxt "field:ir.model.access,perm_write:"
 msgid "Write Access"
-msgstr "Schrijfrecht"
+msgstr "写入"
 
 msgctxt "field:ir.model.access,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.model.access,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.access,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.button,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.button,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.model.button,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:ir.model.button,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.model.button,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
-#, fuzzy
 msgctxt "field:ir.model.button,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.model.button,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.model.button,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.button,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.data,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.data,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.model.data,db_id:"
 msgid "Resource ID"
-msgstr "Middel ID"
+msgstr "资源 ID"
 
 msgctxt "field:ir.model.data,fs_id:"
 msgid "Identifier on File System"
-msgstr "Kenmerk voor bestandssysteem"
+msgstr "文件系统标识"
 
 msgctxt "field:ir.model.data,fs_values:"
 msgid "Values on File System"
-msgstr ""
+msgstr "文件系统值"
 
 msgctxt "field:ir.model.data,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.model.data,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.model.data,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
 msgctxt "field:ir.model.data,noupdate:"
 msgid "No Update"
-msgstr "Niet bij te werken"
+msgstr "不更新"
 
 msgctxt "field:ir.model.data,out_of_sync:"
 msgid "Out of Sync"
-msgstr ""
+msgstr "未同步"
 
 msgctxt "field:ir.model.data,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.model.data,values:"
 msgid "Values"
-msgstr "Waarden"
+msgstr "值"
 
 msgctxt "field:ir.model.data,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.data,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.field,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.field,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.model.field,field_description:"
 msgid "Field Description"
-msgstr "Veld omschrijving"
+msgstr "数据描述"
 
 msgctxt "field:ir.model.field,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:ir.model.field,help:"
 msgid "Help"
-msgstr "Help"
+msgstr "帮助"
 
 msgctxt "field:ir.model.field,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.model.field,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.model.field,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
 msgctxt "field:ir.model.field,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.model.field,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.model.field,relation:"
 msgid "Model Relation"
-msgstr "Model relatie"
+msgstr "模型关联"
 
 msgctxt "field:ir.model.field,ttype:"
 msgid "Field Type"
-msgstr "Veld type"
+msgstr "数据类型"
 
 msgctxt "field:ir.model.field,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.field,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.field.access,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.field.access,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,description:"
 msgid "Description"
-msgstr "Specificatie"
+msgstr "描述"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,field:"
 msgid "Field"
-msgstr "Veld"
+msgstr "数据"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.model.field.access,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,perm_create:"
 msgid "Create Access"
-msgstr "Mag aanmaken"
+msgstr "新建"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,perm_delete:"
 msgid "Delete Access"
-msgstr "Toegang verwijderen"
+msgstr "删除"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,perm_read:"
 msgid "Read Access"
-msgstr "Leesrecht"
+msgstr "读取"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,perm_write:"
 msgid "Write Access"
-msgstr "Schrijfrecht"
+msgstr "写入"
 
-#, fuzzy
 msgctxt "field:ir.model.field.access,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.model.field.access,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.field.access,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.print_model_graph.start,filter:"
 msgid "Filter"
-msgstr ""
+msgstr "筛选"
 
 msgctxt "field:ir.model.print_model_graph.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.model.print_model_graph.start,level:"
 msgid "Level"
-msgstr ""
+msgstr "层级"
 
 msgctxt "field:ir.module,childs:"
 msgid "Childs"
-msgstr ""
+msgstr "子项"
 
 msgctxt "field:ir.module,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.module,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.module,dependencies:"
 msgid "Dependencies"
-msgstr ""
+msgstr "依赖"
 
 msgctxt "field:ir.module,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module,name:"
 msgid "Name"
-msgstr ""
+msgstr "名称"
 
 msgctxt "field:ir.module,parents:"
 msgid "Parents"
-msgstr ""
+msgstr "父级"
 
 msgctxt "field:ir.module,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "名称"
 
 msgctxt "field:ir.module,state:"
 msgid "State"
-msgstr ""
+msgstr "状态"
 
 msgctxt "field:ir.module,version:"
 msgid "Version"
-msgstr ""
+msgstr "版本"
 
 msgctxt "field:ir.module,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.module,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.module.config_wizard.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.config_wizard.first,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.config_wizard.item,action:"
 msgid "Action"
-msgstr ""
+msgstr "动作"
 
 msgctxt "field:ir.module.config_wizard.item,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.module.config_wizard.item,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.module.config_wizard.item,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.config_wizard.item,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "名称"
 
 msgctxt "field:ir.module.config_wizard.item,sequence:"
 msgid "Sequence"
-msgstr ""
+msgstr "序列"
 
 msgctxt "field:ir.module.config_wizard.item,state:"
 msgid "State"
-msgstr ""
+msgstr "状态"
 
 msgctxt "field:ir.module.config_wizard.item,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.module.config_wizard.item,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.module.config_wizard.other,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.config_wizard.other,percentage:"
 msgid "Percentage"
-msgstr ""
+msgstr "百分比"
 
 msgctxt "field:ir.module.dependency,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.module.dependency,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "添加用户"
 
 msgctxt "field:ir.module.dependency,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.dependency,module:"
 msgid "Module"
-msgstr ""
+msgstr "模块"
 
 msgctxt "field:ir.module.dependency,name:"
 msgid "Name"
-msgstr ""
+msgstr "名称"
 
 msgctxt "field:ir.module.dependency,rec_name:"
 msgid "Name"
-msgstr ""
+msgstr "名称"
 
 msgctxt "field:ir.module.dependency,state:"
 msgid "State"
-msgstr ""
+msgstr "状态"
 
 msgctxt "field:ir.module.dependency,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.module.dependency,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.module.install_upgrade.done,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.install_upgrade.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.module.install_upgrade.start,module_info:"
 msgid "Modules to update"
+msgstr "待更新模块"
+
+#, fuzzy
+msgctxt "field:ir.note,create_date:"
+msgid "Create Date"
+msgstr "创建日期:"
+
+#, fuzzy
+msgctxt "field:ir.note,create_uid:"
+msgid "Create User"
+msgstr "创建者"
+
+#, fuzzy
+msgctxt "field:ir.note,id:"
+msgid "ID"
+msgstr "标识"
+
+#, fuzzy
+msgctxt "field:ir.note,last_modification:"
+msgid "Last Modification"
+msgstr "最近更改"
+
+#, fuzzy
+msgctxt "field:ir.note,last_user:"
+msgid "Last User"
+msgstr "最近用户"
+
+msgctxt "field:ir.note,message:"
+msgid "Message"
 msgstr ""
 
-msgctxt "field:ir.property,create_date:"
+msgctxt "field:ir.note,message_wrapped:"
+msgid "Message"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,rec_name:"
+msgid "Name"
+msgstr "名称"
+
+#, fuzzy
+msgctxt "field:ir.note,resource:"
+msgid "Resource"
+msgstr "附件文档资源"
+
+msgctxt "field:ir.note,unread:"
+msgid "Unread"
+msgstr ""
+
+#, fuzzy
+msgctxt "field:ir.note,write_date:"
+msgid "Write Date"
+msgstr "写入日期"
+
+#, fuzzy
+msgctxt "field:ir.note,write_uid:"
+msgid "Write User"
+msgstr "写入帐号"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_date:"
 msgid "Create Date"
+msgstr "创建日期:"
+
+#, fuzzy
+msgctxt "field:ir.note.read,create_uid:"
+msgid "Create User"
+msgstr "创建者"
+
+#, fuzzy
+msgctxt "field:ir.note.read,id:"
+msgid "ID"
+msgstr "标识"
+
+msgctxt "field:ir.note.read,note:"
+msgid "Note"
 msgstr ""
 
+#, fuzzy
+msgctxt "field:ir.note.read,rec_name:"
+msgid "Name"
+msgstr "名称"
+
+#, fuzzy
+msgctxt "field:ir.note.read,user:"
+msgid "User"
+msgstr "用户"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_date:"
+msgid "Write Date"
+msgstr "写入日期"
+
+#, fuzzy
+msgctxt "field:ir.note.read,write_uid:"
+msgid "Write User"
+msgstr "写入帐号"
+
+msgctxt "field:ir.property,create_date:"
+msgid "Create Date"
+msgstr "创建日期"
+
 msgctxt "field:ir.property,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "添加用户"
 
 msgctxt "field:ir.property,field:"
 msgid "Field"
-msgstr "Veld"
+msgstr "数据"
 
 msgctxt "field:ir.property,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.property,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.property,res:"
 msgid "Resource"
-msgstr "Middel"
+msgstr "资源"
 
 msgctxt "field:ir.property,value:"
 msgid "Value"
-msgstr "Waarde"
+msgstr "值"
 
 msgctxt "field:ir.property,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.property,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.rule,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.rule,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "添加用户"
 
-#, fuzzy
 msgctxt "field:ir.rule,domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "field:ir.rule,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.rule,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.rule,rule_group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.rule,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.rule,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.rule.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.rule.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.rule.group,default_p:"
 msgid "Default"
-msgstr "Standaard"
+msgstr "某人"
 
 msgctxt "field:ir.rule.group,global_p:"
 msgid "Global"
-msgstr "Globaal"
+msgstr "全局"
 
 msgctxt "field:ir.rule.group,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:ir.rule.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.rule.group,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.rule.group,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.rule.group,perm_create:"
 msgid "Create Access"
-msgstr "Mag aanmaken"
+msgstr "新建"
 
 msgctxt "field:ir.rule.group,perm_delete:"
 msgid "Delete Access"
-msgstr "Toegang verwijderen"
+msgstr "删除"
 
 msgctxt "field:ir.rule.group,perm_read:"
 msgid "Read Access"
-msgstr "Leesrecht"
+msgstr "读取"
 
 msgctxt "field:ir.rule.group,perm_write:"
 msgid "Write Access"
-msgstr "Schrijfrecht"
+msgstr "写入"
 
 msgctxt "field:ir.rule.group,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.rule.group,rules:"
 msgid "Tests"
-msgstr "Testen"
+msgstr "测试"
 
 msgctxt "field:ir.rule.group,users:"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
 msgctxt "field:ir.rule.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.rule.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.sequence,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.sequence,code:"
 msgid "Sequence Code"
-msgstr "Reeks code"
+msgstr "序列编号"
 
 msgctxt "field:ir.sequence,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.sequence,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.sequence,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.sequence,last_timestamp:"
 msgid "Last Timestamp"
-msgstr "Laatste tijdmarkering"
+msgstr "上一时间戳"
 
 msgctxt "field:ir.sequence,name:"
 msgid "Sequence Name"
-msgstr "Reeks naam"
+msgstr "序列名"
 
 msgctxt "field:ir.sequence,number_increment:"
 msgid "Increment Number"
-msgstr "Oplopende stap"
+msgstr "递增数"
 
 msgctxt "field:ir.sequence,number_next:"
 msgid "Next Number"
-msgstr "Volgende nummer"
+msgstr "下一个数"
 
-#, fuzzy
 msgctxt "field:ir.sequence,number_next_internal:"
 msgid "Next Number"
-msgstr "Volgende nummer"
+msgstr "下一个数"
 
 msgctxt "field:ir.sequence,padding:"
 msgid "Number padding"
-msgstr "Voorloopnullen"
+msgstr "数字补白"
 
 msgctxt "field:ir.sequence,prefix:"
 msgid "Prefix"
-msgstr "Voorvoegsel"
+msgstr "前缀"
 
 msgctxt "field:ir.sequence,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.sequence,suffix:"
 msgid "Suffix"
-msgstr "Toevoeging"
+msgstr "后缀"
 
 msgctxt "field:ir.sequence,timestamp_offset:"
 msgid "Timestamp Offset"
-msgstr "Tijdmarkering verschuiving"
+msgstr "时间偏移"
 
 msgctxt "field:ir.sequence,timestamp_rounding:"
 msgid "Timestamp Rounding"
-msgstr "Tijdmarkering afronding"
+msgstr "整数时间"
 
 msgctxt "field:ir.sequence,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.sequence,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.sequence,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.sequence.strict,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.sequence.strict,code:"
 msgid "Sequence Code"
-msgstr "Reeks code"
+msgstr "序列编号"
 
 msgctxt "field:ir.sequence.strict,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.sequence.strict,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "添加用户"
 
 msgctxt "field:ir.sequence.strict,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.sequence.strict,last_timestamp:"
 msgid "Last Timestamp"
-msgstr "Laatste tijdmarkering"
+msgstr "上一时间戳"
 
 msgctxt "field:ir.sequence.strict,name:"
 msgid "Sequence Name"
-msgstr "Reeks naam"
+msgstr "序列名"
 
 msgctxt "field:ir.sequence.strict,number_increment:"
 msgid "Increment Number"
-msgstr "Oplopende stap"
+msgstr "递增数"
 
 msgctxt "field:ir.sequence.strict,number_next:"
 msgid "Next Number"
-msgstr "Volgende nummer"
+msgstr "下一个数"
 
-#, fuzzy
 msgctxt "field:ir.sequence.strict,number_next_internal:"
 msgid "Next Number"
-msgstr "Volgende nummer"
+msgstr "下一个数"
 
 msgctxt "field:ir.sequence.strict,padding:"
 msgid "Number padding"
-msgstr "Voorloopnullen"
+msgstr "数字补白"
 
 msgctxt "field:ir.sequence.strict,prefix:"
 msgid "Prefix"
-msgstr "Voorvoegsel"
+msgstr "前缀"
 
 msgctxt "field:ir.sequence.strict,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.sequence.strict,suffix:"
 msgid "Suffix"
-msgstr "Toevoeging"
+msgstr "后缀"
 
 msgctxt "field:ir.sequence.strict,timestamp_offset:"
 msgid "Timestamp Offset"
-msgstr "Tijdmarkering verschuiving"
+msgstr "时间偏移"
 
 msgctxt "field:ir.sequence.strict,timestamp_rounding:"
 msgid "Timestamp Rounding"
-msgstr "Tijdmarkering afronding"
+msgstr "整数时间"
 
 msgctxt "field:ir.sequence.strict,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.sequence.strict,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.sequence.strict,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.sequence.type,code:"
 msgid "Sequence Code"
-msgstr "Reeks code"
+msgstr "序列编号"
 
 msgctxt "field:ir.sequence.type,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.sequence.type,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "添加用户"
 
 msgctxt "field:ir.sequence.type,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.sequence.type,name:"
 msgid "Sequence Name"
-msgstr "Reeks naam"
+msgstr "序列名"
 
 msgctxt "field:ir.sequence.type,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.sequence.type,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.sequence.type,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.session,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.session,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.session,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.session,key:"
 msgid "Key"
-msgstr ""
+msgstr "密匙"
 
-#, fuzzy
 msgctxt "field:ir.session,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.session,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.session,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.session.wizard,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.session.wizard,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.session.wizard,data:"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
 msgctxt "field:ir.session.wizard,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.session.wizard,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.session.wizard,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.session.wizard,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.translation,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.translation,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.translation,fuzzy:"
 msgid "Fuzzy"
-msgstr "Onzeker"
+msgstr "模糊"
 
 msgctxt "field:ir.translation,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation,lang:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
 msgctxt "field:ir.translation,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.translation,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
 msgctxt "field:ir.translation,name:"
 msgid "Field Name"
-msgstr "Veldnaam"
+msgstr "列名"
 
 msgctxt "field:ir.translation,overriding_module:"
 msgid "Overriding Module"
-msgstr ""
+msgstr "来源模块"
 
 msgctxt "field:ir.translation,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.translation,res_id:"
 msgid "Resource ID"
-msgstr "Middel ID"
+msgstr "资源 ID"
 
 msgctxt "field:ir.translation,src:"
 msgid "Source"
-msgstr "Bron"
+msgstr "源"
 
 msgctxt "field:ir.translation,src_md5:"
 msgid "Source MD5"
-msgstr ""
+msgstr "源 MD5"
 
 msgctxt "field:ir.translation,type:"
 msgid "Type"
-msgstr "Type"
+msgstr "类型"
 
 msgctxt "field:ir.translation,value:"
 msgid "Translation Value"
-msgstr "Vertaling"
+msgstr "翻译"
 
 msgctxt "field:ir.translation,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.translation,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.translation.clean.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation.clean.succeed,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation.export.result,file:"
 msgid "File"
-msgstr ""
+msgstr "文件"
 
 msgctxt "field:ir.translation.export.result,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation.export.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.translation.export.start,language:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
-#, fuzzy
 msgctxt "field:ir.translation.export.start,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
 msgctxt "field:ir.translation.set.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation.set.succeed,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.translation.update.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.translation.update.start,language:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
 msgctxt "field:ir.trigger,action_function:"
 msgid "Action Function"
-msgstr "Actiefunctie"
+msgstr "动作方法"
 
 msgctxt "field:ir.trigger,action_model:"
 msgid "Action Model"
-msgstr "Actie model"
+msgstr "动作模型"
 
 msgctxt "field:ir.trigger,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.trigger,condition:"
 msgid "Condition"
-msgstr "Voorwaarde"
+msgstr "条件"
 
 msgctxt "field:ir.trigger,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.trigger,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.trigger,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.trigger,limit_number:"
 msgid "Limit Number"
-msgstr "Begrenzing nummer"
+msgstr "数量限制"
 
 msgctxt "field:ir.trigger,minimum_time_delay:"
 msgid "Minimum Delay"
-msgstr ""
+msgstr "最小延迟"
 
 msgctxt "field:ir.trigger,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.trigger,name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.trigger,on_create:"
 msgid "On Create"
-msgstr "Bij aanmaken"
+msgstr "新建触发"
 
 msgctxt "field:ir.trigger,on_delete:"
 msgid "On Delete"
-msgstr "Bij verwijderen"
+msgstr "删除触发"
 
 msgctxt "field:ir.trigger,on_time:"
 msgid "On Time"
-msgstr "Op tijd"
+msgstr "时基触发"
 
 msgctxt "field:ir.trigger,on_write:"
 msgid "On Write"
-msgstr "Bij muteren"
+msgstr "写入触发"
 
 msgctxt "field:ir.trigger,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.trigger,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.trigger,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.trigger.log,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.trigger.log,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.trigger.log,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.trigger.log,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.trigger.log,record_id:"
 msgid "Record ID"
-msgstr "Item ID"
+msgstr "记录标识"
 
 msgctxt "field:ir.trigger.log,trigger:"
 msgid "Trigger"
-msgstr "Starter"
+msgstr "触发器"
 
 msgctxt "field:ir.trigger.log,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.trigger.log,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.icon,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.icon,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.ui.icon,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.ui.icon,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.ui.icon,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
-#, fuzzy
 msgctxt "field:ir.ui.icon,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.ui.icon,path:"
 msgid "SVG Path"
-msgstr ""
+msgstr "SVG Path"
 
-#, fuzzy
 msgctxt "field:ir.ui.icon,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.ui.icon,sequence:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
 msgctxt "field:ir.ui.icon,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.icon,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.menu,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
 msgctxt "field:ir.ui.menu,action_keywords:"
 msgid "Action Keywords"
-msgstr ""
+msgstr "动作关键词"
 
 msgctxt "field:ir.ui.menu,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.ui.menu,childs:"
 msgid "Children"
-msgstr "Onderliggende niveaus"
+msgstr "子项"
 
 msgctxt "field:ir.ui.menu,complete_name:"
 msgid "Complete Name"
-msgstr "Volledige naam"
+msgstr "全名"
 
 msgctxt "field:ir.ui.menu,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.menu,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.ui.menu,favorite:"
 msgid "Favorite"
-msgstr ""
+msgstr "收藏"
 
 msgctxt "field:ir.ui.menu,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:ir.ui.menu,icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "field:ir.ui.menu,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.ui.menu,name:"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
 msgctxt "field:ir.ui.menu,parent:"
 msgid "Parent Menu"
-msgstr "Hoofdmenu"
+msgstr "上一级菜单"
 
 msgctxt "field:ir.ui.menu,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.ui.menu,sequence:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
 msgctxt "field:ir.ui.menu,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.menu,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.menu.favorite,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.menu.favorite,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.ui.menu.favorite,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu.favorite,menu:"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu.favorite,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu.favorite,sequence:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu.favorite,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:ir.ui.menu.favorite,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.menu.favorite,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.view,arch:"
 msgid "View Architecture"
-msgstr "Bekijk opbouw"
+msgstr "视图层次"
 
 msgctxt "field:ir.ui.view,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.view,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.ui.view,data:"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
 msgctxt "field:ir.ui.view,domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "field:ir.ui.view,field_childs:"
 msgid "Children Field"
-msgstr "Veld onderliggende niveaus"
+msgstr "子项"
 
 msgctxt "field:ir.ui.view,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.ui.view,inherit:"
 msgid "Inherited View"
-msgstr "Aanzicht overnemen"
+msgstr "继承的视图"
 
 msgctxt "field:ir.ui.view,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.ui.view,module:"
 msgid "Module"
-msgstr "Module"
+msgstr "模块"
 
-#, fuzzy
 msgctxt "field:ir.ui.view,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.ui.view,priority:"
 msgid "Priority"
-msgstr "Prioriteit"
+msgstr "优先级"
 
 msgctxt "field:ir.ui.view,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.ui.view,type:"
 msgid "View Type"
-msgstr "Aanzicht type"
+msgstr "视图类型"
 
 msgctxt "field:ir.ui.view,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.view,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.view.show.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.ui.view_search,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.view_search,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_search,domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "field:ir.ui.view_search,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_search,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_search,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_search,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_search,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:ir.ui.view_search,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.view_search,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.view_tree_state,child_name:"
 msgid "Child Name"
-msgstr ""
+msgstr "子项名称"
 
 msgctxt "field:ir.ui.view_tree_state,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.view_tree_state,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_tree_state,domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "field:ir.ui.view_tree_state,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_tree_state,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.ui.view_tree_state,nodes:"
 msgid "Expanded Nodes"
-msgstr ""
+msgstr "展开节点"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_tree_state,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.ui.view_tree_state,selected_nodes:"
 msgid "Selected Nodes"
-msgstr ""
+msgstr "选中节点"
 
-#, fuzzy
 msgctxt "field:ir.ui.view_tree_state,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:ir.ui.view_tree_state,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.view_tree_state,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.view_tree_width,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.view_tree_width,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.ui.view_tree_width,field:"
 msgid "Field"
-msgstr "Veld"
+msgstr "数据"
 
 msgctxt "field:ir.ui.view_tree_width,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:ir.ui.view_tree_width,model:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "field:ir.ui.view_tree_width,rec_name:"
 msgid "Name"
-msgstr "Naam"
+msgstr "名称"
 
 msgctxt "field:ir.ui.view_tree_width,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:ir.ui.view_tree_width,width:"
 msgid "Width"
-msgstr "Breedte"
+msgstr "宽"
 
 msgctxt "field:ir.ui.view_tree_width,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.view_tree_width,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "help:ir.action.act_window,limit:"
 msgid "Default limit for the list view"
-msgstr "Standaard begrenzing voor dit aanzicht"
+msgstr "列表视图默认限制"
 
 msgctxt "help:ir.action.act_window,search_value:"
 msgid "Default search criteria for the list view"
-msgstr "Standaard zoekopdracht voor lijst"
+msgstr "列表视图默认搜索表达式"
 
 msgctxt "help:ir.action.act_window,window_name:"
 msgid "Use the action name as window name"
-msgstr "Gebruik de naam van de actie als schermnaam"
+msgstr "动作名做窗体名"
 
 msgctxt "help:ir.action.report,email:"
 msgid ""
 "Python dictonary where keys define \"to\" \"cc\" \"subject\"\n"
 "Example: {'to': 'test at example.com', 'cc': 'user at example.com'}"
 msgstr ""
+"定义键 \"to\" \"cc\" \"subject\"的python dictionary\n"
+"如: {'to': 'test at example.com', 'cc': 'user at example.com'}"
 
 msgctxt "help:ir.action.report,extension:"
 msgid ""
 "Leave empty for the same as template, see unoconv documentation for "
 "compatible format"
-msgstr ""
+msgstr "参考unoconv文档有关格式部分,模版空白不要改动"
 
 msgctxt "help:ir.action.wizard,window:"
 msgid "Run wizard in a new window"
-msgstr "Start assistent in nieuw venster"
+msgstr "打开新窗口运行向导"
 
 msgctxt "help:ir.cron,number_calls:"
 msgid ""
 "Number of times the function is called, a negative number indicates that the"
 " function will always be called"
-msgstr ""
+msgstr "方法被调用的次数,负数表示方法总是被调用"
 
 msgctxt "help:ir.cron,request_user:"
 msgid "The user who will receive requests in case of failure"
-msgstr "De gebruiker die de verzoeken krijgt in geval van falen"
+msgstr "运行失败后由哪个用户接收请求"
 
 msgctxt "help:ir.cron,user:"
 msgid "The user used to execute this action"
-msgstr "De gebruiker die gebruikt wordt voor deze actie"
+msgstr "执行动作的用户"
 
 msgctxt "help:ir.lang,code:"
 msgid "RFC 4646 tag: http://tools.ietf.org/html/rfc4646"
-msgstr ""
+msgstr "RFC 4646 tag: http://tools.ietf.org/html/rfc4646"
 
 msgctxt "help:ir.model,module:"
 msgid "Module in which this model is defined"
-msgstr "Module waarin dit veld is gedefinieerd"
+msgstr "定义该模型的模块"
 
 msgctxt "help:ir.model.data,db_id:"
 msgid "The id of the record in the database."
-msgstr "Het ID van het item in de database."
+msgstr "数据库里的记录ID"
 
 msgctxt "help:ir.model.data,fs_id:"
 msgid "The id of the record as known on the file system."
-msgstr "Het ID van het item zoals bekend in het bestandssysteem."
+msgstr "文件系统里的记录ID"
 
 msgctxt "help:ir.model.field,module:"
 msgid "Module in which this field is defined"
-msgstr "Module waarin dit veld is gedefinieerd"
+msgstr "定义该数据的模块"
 
 msgctxt "help:ir.model.print_model_graph.start,filter:"
 msgid ""
 "Entering a Python Regular Expression will exclude matching models from the "
 "graph."
-msgstr ""
+msgstr "输入Python表达式从图表中排除匹配的的模型"
 
 msgctxt "help:ir.rule,domain:"
 msgid ""
 "Domain is evaluated with a PYSON context containing:\n"
 "- \"user\" as the current user"
-msgstr ""
+msgstr "PYSON场景满足当前用户名为“用户名”, 域配置生效."
 
 msgctxt "help:ir.rule.group,default_p:"
 msgid "Add this rule to all users by default"
-msgstr "Voeg deze regel standaard toe bij alle gebruikers"
+msgstr "默认向所有用户启用本规则"
 
 msgctxt "help:ir.rule.group,global_p:"
 msgid ""
 "Make the rule global \n"
 "so every users must follow this rule"
-msgstr "Maak de regel globaal"
+msgstr ""
+"本规则设定为“全局”\n"
+" 对所有用户有效"
 
 msgctxt "help:ir.rule.group,rules:"
 msgid "The rule is satisfied if at least one test is True"
-msgstr "De regel is waar als tenminste aan één voorwaarde wordt voldaan"
+msgstr "任意一项测试结果为真,即判断符合规则."
 
 msgctxt "help:ir.trigger,condition:"
 msgid ""
 "A PYSON statement evaluated with record represented by \"self\"\n"
 "It triggers the action if true."
 msgstr ""
+"用“self”提交的数据校验PYSON声明完成\n"
+" 符合条件则触发该动作."
 
 msgctxt "help:ir.trigger,limit_number:"
 msgid ""
 "Limit the number of call to \"Action Function\" by records.\n"
 "0 for no limit."
 msgstr ""
-"Beperk het aantal aanroepen van \"Uitvoerende functie\" door items.\n"
-"Gebruik 0 voor geen beperking."
+"限制数据调用“动作方法”次数\n"
+" 0表示无限制."
 
 msgctxt "help:ir.trigger,minimum_time_delay:"
 msgid ""
 "Set a minimum time delay between call to \"Action Function\" for the same record.\n"
 "empty for no delay."
 msgstr ""
+"设置对相同数据调用\"动作方法\" 的最小间隔时间\n"
+" 留空表示不限制"
 
 msgctxt "help:ir.ui.view_search,domain:"
 msgid "The PYSON domain"
-msgstr ""
+msgstr "PYSON 域"
 
 msgctxt "model:ir.action,name:"
 msgid "Action"
-msgstr "Actie"
+msgstr "动作"
 
 msgctxt "model:ir.action,name:act_action_act_window_form"
 msgid "Window Actions"
-msgstr "Schermacties"
+msgstr "窗口动作"
 
 msgctxt "model:ir.action,name:act_action_form"
 msgid "Actions"
-msgstr "Acties"
+msgstr "动作"
 
 msgctxt "model:ir.action,name:act_action_report_form"
 msgid "Reports"
-msgstr "Rapportage"
+msgstr "报表"
 
 msgctxt "model:ir.action,name:act_action_url_form"
 msgid "URLs"
-msgstr "URL's\n"
+msgstr "URL"
 
 msgctxt "model:ir.action,name:act_action_wizard_form"
 msgid "Wizards"
-msgstr "Assistenten"
+msgstr "向导"
 
 msgctxt "model:ir.action,name:act_attachment_form"
 msgid "Attachments"
-msgstr "Bijlagen"
+msgstr "附件文档"
 
 msgctxt "model:ir.action,name:act_config_wizard_item_form"
 msgid "Config Wizard Items"
-msgstr "Conf. assistent items"
+msgstr "设置向导项目"
 
 msgctxt "model:ir.action,name:act_cron_form"
 msgid "Scheduled Actions"
-msgstr "Geplande acties"
+msgstr "计划动作"
 
 msgctxt "model:ir.action,name:act_export_form"
 msgid "Exports"
-msgstr "Export"
+msgstr "导出"
 
 msgctxt "model:ir.action,name:act_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "图标"
 
 msgctxt "model:ir.action,name:act_lang_form"
 msgid "Languages"
-msgstr "Talen"
+msgstr "语言"
 
-#, fuzzy
 msgctxt "model:ir.action,name:act_menu_list"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
 msgctxt "model:ir.action,name:act_menu_tree"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
 msgctxt "model:ir.action,name:act_model_access_form"
 msgid "Models Access"
-msgstr "Toegang tot modellen"
+msgstr "模型权限"
 
 msgctxt "model:ir.action,name:act_model_button_form"
 msgid "Buttons"
-msgstr ""
+msgstr "按钮"
 
 msgctxt "model:ir.action,name:act_model_data_form"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
 msgctxt "model:ir.action,name:act_model_field_access_form"
 msgid "Fields Access"
-msgstr ""
+msgstr "数据权限"
 
 msgctxt "model:ir.action,name:act_model_fields_form"
 msgid "Fields"
-msgstr "Velden"
+msgstr "数据"
 
 msgctxt "model:ir.action,name:act_model_form"
 msgid "Models"
-msgstr "Modellen"
+msgstr "模型"
 
 msgctxt "model:ir.action,name:act_module_config"
 msgid "Configure Modules"
-msgstr ""
+msgstr "设置模块"
 
 msgctxt "model:ir.action,name:act_module_config_wizard"
 msgid "Module Configuration"
-msgstr "Module configuratie"
+msgstr "模块设置"
 
 msgctxt "model:ir.action,name:act_module_form"
 msgid "Modules"
-msgstr "Modulen"
+msgstr "模块"
 
 msgctxt "model:ir.action,name:act_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
-msgstr "Voer installatie / bijwerken uit"
+msgstr "执行未完成的”安装“ “升级”"
+
+msgctxt "model:ir.action,name:act_note_form"
+msgid "Notes"
+msgstr ""
 
 msgctxt "model:ir.action,name:act_property_form"
 msgid "Properties"
-msgstr "Eigenschappen"
+msgstr "属性"
 
 msgctxt "model:ir.action,name:act_property_form_default"
 msgid "Default Properties"
-msgstr "Standaard eigenschappen"
+msgstr "默认属性"
 
 msgctxt "model:ir.action,name:act_rule_group_form"
 msgid "Record Rules"
-msgstr "Item regels"
+msgstr "数据规则"
 
 msgctxt "model:ir.action,name:act_sequence_form"
 msgid "Sequences"
-msgstr "Reeksen"
+msgstr "序列"
 
 msgctxt "model:ir.action,name:act_sequence_strict_form"
 msgid "Sequences Strict"
-msgstr "Vaste reeksen"
+msgstr "严格序列"
 
 msgctxt "model:ir.action,name:act_sequence_type_form"
 msgid "Sequence Types"
-msgstr "Reeks typen"
+msgstr "序列类型"
 
 msgctxt "model:ir.action,name:act_translation_clean"
 msgid "Clean Translations"
-msgstr "Vertalingen opschonen"
+msgstr "清理翻译"
 
 msgctxt "model:ir.action,name:act_translation_export"
 msgid "Export Translations"
-msgstr "Vertalingen exporteren"
+msgstr "导出翻译条目"
 
 msgctxt "model:ir.action,name:act_translation_form"
 msgid "Translations"
-msgstr "Vertalingen"
+msgstr "翻译"
 
 msgctxt "model:ir.action,name:act_translation_set"
 msgid "Set Report Translations"
-msgstr ""
+msgstr "设置报表翻译"
 
 msgctxt "model:ir.action,name:act_translation_update"
 msgid "Synchronize Translations"
-msgstr "Vertaling synchroniseren"
+msgstr "使翻译生效"
 
 msgctxt "model:ir.action,name:act_trigger_form"
 msgid "Triggers"
-msgstr "Starters"
+msgstr "触发器"
 
 msgctxt "model:ir.action,name:act_view_form"
 msgid "Views"
-msgstr "Aanzichten"
+msgstr "视图"
 
 msgctxt "model:ir.action,name:act_view_search"
 msgid "View Search"
-msgstr ""
+msgstr "搜索视图"
 
 msgctxt "model:ir.action,name:act_view_show"
 msgid "Show View"
-msgstr ""
+msgstr "显示视图"
 
 msgctxt "model:ir.action,name:act_view_tree_state"
 msgid "Tree State"
-msgstr ""
+msgstr "三态"
 
 msgctxt "model:ir.action,name:act_view_tree_width_form"
 msgid "View Tree Width"
-msgstr "Aanzicht boomstructuurbreedte"
+msgstr "导航树宽度"
 
 msgctxt "model:ir.action,name:print_model_graph"
 msgid "Graph"
-msgstr "Grafiek"
+msgstr "图表"
 
 msgctxt "model:ir.action,name:report_model_graph"
 msgid "Graph"
-msgstr "Grafiek"
+msgstr "图表"
+
+msgctxt "model:ir.action,name:report_model_workflow_graph"
+msgid "Workflow Graph"
+msgstr ""
 
 msgctxt "model:ir.action.act_window,name:"
 msgid "Action act window"
-msgstr "Actie uitvoerend scherm"
+msgstr "动作窗体"
 
 msgctxt "model:ir.action.act_window.domain,name:"
 msgid "Action act window domain"
-msgstr ""
+msgstr "动作窗体域设置"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_model_data_form_domain_all"
 msgid "All"
-msgstr ""
+msgstr "全部"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_model_data_form_domain_out_of_sync"
 msgid "Out of Sync"
-msgstr ""
+msgstr "未同步"
 
 msgctxt "model:ir.action.act_window.view,name:"
 msgid "Action act window view"
-msgstr "Actie uitvoerend schermaanzicht"
+msgstr "动作窗体视图"
 
 msgctxt "model:ir.action.keyword,name:"
 msgid "Action keyword"
-msgstr "Actietrefwoord"
+msgstr "动作关键词"
 
 msgctxt "model:ir.action.report,name:"
 msgid "Action report"
-msgstr "Actie rapport"
+msgstr "动作报表"
 
 msgctxt "model:ir.action.url,name:"
 msgid "Action URL"
-msgstr "Actie URL"
+msgstr "动作 Url"
 
 msgctxt "model:ir.action.wizard,name:"
 msgid "Action wizard"
-msgstr "Actie assistent"
+msgstr "动作向导"
 
 msgctxt "model:ir.attachment,name:"
 msgid "Attachment"
-msgstr "Bijlage"
+msgstr "附件文档"
 
 msgctxt "model:ir.cache,name:"
 msgid "Cache"
-msgstr "Tijdelijk geheugen"
+msgstr "缓存"
 
-#, fuzzy
 msgctxt "model:ir.configuration,name:"
 msgid "Configuration"
-msgstr "Instellingen"
+msgstr "设置"
 
 msgctxt "model:ir.cron,name:"
 msgid "Cron"
-msgstr "Cyclische opdracht"
+msgstr "Cron"
 
 msgctxt "model:ir.date,name:"
 msgid "Date"
-msgstr "Datum"
+msgstr "日期"
 
 msgctxt "model:ir.export,name:"
 msgid "Export"
-msgstr "Exporteren"
+msgstr "导出"
 
 msgctxt "model:ir.export.line,name:"
 msgid "Export line"
-msgstr "Exporterregel"
+msgstr "导出行"
 
 msgctxt "model:ir.lang,name:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
 msgctxt "model:ir.lang,name:lang_ar"
 msgid "Spanish (Argentina)"
-msgstr ""
+msgstr "西班牙语(阿根廷)"
 
 msgctxt "model:ir.lang,name:lang_bg"
 msgid "Bulgarian"
-msgstr ""
+msgstr "保加利亚语"
 
 msgctxt "model:ir.lang,name:lang_ca"
 msgid "Català"
-msgstr ""
+msgstr "加泰罗尼亚语"
 
 msgctxt "model:ir.lang,name:lang_cs"
 msgid "Czech"
-msgstr "Tsjechisch"
+msgstr "捷克语"
 
 msgctxt "model:ir.lang,name:lang_de"
 msgid "German"
-msgstr "Duits"
+msgstr "德语"
 
 msgctxt "model:ir.lang,name:lang_ec"
 msgid "Spanish (Ecuador)"
-msgstr ""
+msgstr "西班牙语(厄瓜多尔)"
 
 msgctxt "model:ir.lang,name:lang_en"
 msgid "English"
-msgstr "Engels"
+msgstr "英语"
 
 msgctxt "model:ir.lang,name:lang_es"
 msgid "Spanish (Spain)"
-msgstr "Spaans (Spanje)"
+msgstr "西班牙语(西班牙)"
 
 msgctxt "model:ir.lang,name:lang_es_CO"
 msgid "Spanish (Colombia)"
-msgstr "Spaans (Colombia)"
+msgstr "西班牙语(哥伦比亚)"
 
 msgctxt "model:ir.lang,name:lang_es_MX"
 msgid "Spanish (Mexico)"
-msgstr ""
+msgstr "西班牙语(墨西哥)"
 
 msgctxt "model:ir.lang,name:lang_fr"
 msgid "French"
-msgstr "Frans"
+msgstr "法语"
 
 msgctxt "model:ir.lang,name:lang_hu_HU"
 msgid "Hungarian"
-msgstr ""
+msgstr "匈牙利语"
 
 msgctxt "model:ir.lang,name:lang_it_IT"
 msgid "Italian"
-msgstr ""
+msgstr "意大利语"
 
 msgctxt "model:ir.lang,name:lang_lt"
 msgid "Lithuanian"
-msgstr ""
+msgstr "立陶宛语"
 
 msgctxt "model:ir.lang,name:lang_nl"
 msgid "Dutch"
-msgstr ""
+msgstr "荷兰语"
 
 msgctxt "model:ir.lang,name:lang_pt_BR"
 msgid "Portuguese (Brazil)"
-msgstr ""
+msgstr "葡萄牙语"
 
 msgctxt "model:ir.lang,name:lang_ru"
 msgid "Russian"
-msgstr "Russisch"
+msgstr "俄语"
 
 msgctxt "model:ir.lang,name:lang_sl"
 msgid "Slovenian"
-msgstr ""
+msgstr "斯洛维尼亚语"
 
 msgctxt "model:ir.model,name:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
 msgctxt "model:ir.model.access,name:"
 msgid "Model access"
-msgstr "Toegang tot model"
+msgstr "模型权限"
 
 msgctxt "model:ir.model.button,name:"
 msgid "Model Button"
-msgstr ""
+msgstr "按钮模型"
 
 msgctxt "model:ir.model.data,name:"
 msgid "Model data"
-msgstr "Model gegevens"
+msgstr "模型数据"
 
 msgctxt "model:ir.model.field,name:"
 msgid "Model field"
-msgstr "Model veld"
+msgstr "数据"
 
 msgctxt "model:ir.model.field.access,name:"
 msgid "Model Field Access"
-msgstr ""
+msgstr "数据权限"
 
 msgctxt "model:ir.model.print_model_graph.start,name:"
 msgid "Print Model Graph"
-msgstr ""
+msgstr "打印模型图表"
 
 msgctxt "model:ir.module,name:"
 msgid "Module"
-msgstr ""
+msgstr "模块"
 
 msgctxt "model:ir.module.config_wizard.done,name:"
 msgid "Module Config Wizard Done"
-msgstr ""
+msgstr "模块设置向导完成"
 
 msgctxt "model:ir.module.config_wizard.first,name:"
 msgid "Module Config Wizard First"
-msgstr ""
+msgstr "模块设置向导开始"
 
 msgctxt "model:ir.module.config_wizard.item,name:"
 msgid "Config wizard to run after installing module"
-msgstr ""
+msgstr "设置模块安装完成开始向导"
 
 msgctxt "model:ir.module.config_wizard.other,name:"
 msgid "Module Config Wizard Other"
-msgstr ""
+msgstr "模块设置向导其他"
 
 msgctxt "model:ir.module.dependency,name:"
 msgid "Module dependency"
-msgstr ""
+msgstr "模块依赖关系"
 
 msgctxt "model:ir.module.install_upgrade.done,name:"
 msgid "Module Install Upgrade Done"
-msgstr ""
+msgstr "模块安装升级完成"
 
 msgctxt "model:ir.module.install_upgrade.start,name:"
 msgid "Module Install Upgrade Start"
+msgstr "模块安装升级开始"
+
+msgctxt "model:ir.note,name:"
+msgid "Note"
+msgstr ""
+
+msgctxt "model:ir.note.read,name:"
+msgid "Note Read"
 msgstr ""
 
 msgctxt "model:ir.property,name:"
 msgid "Property"
-msgstr "Eigenschap"
+msgstr "属性"
 
 msgctxt "model:ir.rule,name:"
 msgid "Rule"
-msgstr "Regel"
+msgstr "规则"
 
 msgctxt "model:ir.rule.group,name:"
 msgid "Rule group"
-msgstr "Regelgroep"
+msgstr "规则组"
 
 msgctxt "model:ir.sequence,name:"
 msgid "Sequence"
-msgstr "Reeks"
+msgstr "序列"
 
 msgctxt "model:ir.sequence.strict,name:"
 msgid "Sequence Strict"
-msgstr "Vaste reeks"
+msgstr "严格序列"
 
 msgctxt "model:ir.sequence.type,name:"
 msgid "Sequence type"
-msgstr "Reeks type"
+msgstr "序列类型"
 
 msgctxt "model:ir.session,name:"
 msgid "Session"
-msgstr ""
+msgstr "进程"
 
 msgctxt "model:ir.session.wizard,name:"
 msgid "Session Wizard"
-msgstr ""
+msgstr "进程设置向导"
 
 msgctxt "model:ir.translation,name:"
 msgid "Translation"
-msgstr "Vertaling"
+msgstr "翻译"
 
-#, fuzzy
 msgctxt "model:ir.translation.clean.start,name:"
 msgid "Clean translation"
-msgstr "Start vertalingen opschonen"
+msgstr "翻译"
 
-#, fuzzy
 msgctxt "model:ir.translation.clean.succeed,name:"
 msgid "Clean translation"
-msgstr "Start vertalingen opschonen"
+msgstr "翻译"
 
-#, fuzzy
 msgctxt "model:ir.translation.export.result,name:"
 msgid "Export translation"
-msgstr "Vertaling exporteren - bestand"
+msgstr "导出翻译条目"
 
-#, fuzzy
 msgctxt "model:ir.translation.export.start,name:"
 msgid "Export translation"
-msgstr "Vertaling exporteren - bestand"
+msgstr "导出翻译条目"
 
 msgctxt "model:ir.translation.set.start,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "保存翻译"
 
 msgctxt "model:ir.translation.set.succeed,name:"
 msgid "Set Translation"
-msgstr ""
+msgstr "保存翻译"
 
 msgctxt "model:ir.translation.update.start,name:"
 msgid "Update translation"
-msgstr ""
+msgstr "更新翻译"
 
 msgctxt "model:ir.trigger,name:"
 msgid "Trigger"
-msgstr "Starter"
+msgstr "触发器"
 
 msgctxt "model:ir.trigger.log,name:"
 msgid "Trigger Log"
-msgstr "Starter logboek"
+msgstr "触发器运行日志"
 
-#, fuzzy
 msgctxt "model:ir.ui.icon,name:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "model:ir.ui.menu,name:"
 msgid "UI menu"
-msgstr "Gebruiker menu"
+msgstr "UI 菜单"
 
 msgctxt "model:ir.ui.menu,name:menu_act_action"
 msgid "Actions"
-msgstr "Acties"
+msgstr "动作"
 
 msgctxt "model:ir.ui.menu,name:menu_action"
 msgid "Actions"
-msgstr "Acties"
+msgstr "动作"
 
 msgctxt "model:ir.ui.menu,name:menu_action_act_window"
 msgid "Window Actions"
-msgstr "Schermacties"
+msgstr "窗口动作"
 
 msgctxt "model:ir.ui.menu,name:menu_action_report_form"
 msgid "Reports"
-msgstr "Rapportage"
+msgstr "报表"
 
 msgctxt "model:ir.ui.menu,name:menu_action_url"
 msgid "URLs"
-msgstr "URL's"
+msgstr "URL"
 
 msgctxt "model:ir.ui.menu,name:menu_action_wizard"
 msgid "Wizards"
-msgstr "Assistenten"
+msgstr "向导"
 
 msgctxt "model:ir.ui.menu,name:menu_administration"
 msgid "Administration"
-msgstr "Systeembeheer"
+msgstr "Administration"
 
 msgctxt "model:ir.ui.menu,name:menu_attachment_form"
 msgid "Attachments"
-msgstr "Bijlagen"
+msgstr "附件文档"
 
 msgctxt "model:ir.ui.menu,name:menu_config_wizard_item_form"
 msgid "Config Wizard Items"
-msgstr "Conf. assistent items"
+msgstr "设置向导"
 
 msgctxt "model:ir.ui.menu,name:menu_cron_form"
 msgid "Scheduled Actions"
-msgstr "Geplande acties"
+msgstr "计划动作"
 
 msgctxt "model:ir.ui.menu,name:menu_export_form"
 msgid "Exports"
-msgstr "Export"
+msgstr "导出项目"
 
 msgctxt "model:ir.ui.menu,name:menu_icon_form"
 msgid "Icons"
-msgstr ""
+msgstr "图标"
 
 msgctxt "model:ir.ui.menu,name:menu_ir_sequence_type"
 msgid "Sequence Types"
-msgstr "Reeks typen"
+msgstr "序列类型"
 
 msgctxt "model:ir.ui.menu,name:menu_lang_form"
 msgid "Languages"
-msgstr "Talen"
+msgstr "语言"
 
 msgctxt "model:ir.ui.menu,name:menu_localization"
 msgid "Localization"
-msgstr "Lokalisatie"
+msgstr "地域"
 
-#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_menu_list"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
 msgctxt "model:ir.ui.menu,name:menu_model_access_form"
 msgid "Models Access"
-msgstr "Toegang tot modellen"
+msgstr "模型权限"
 
 msgctxt "model:ir.ui.menu,name:menu_model_button_form"
 msgid "Buttons"
-msgstr ""
+msgstr "按钮"
 
 msgctxt "model:ir.ui.menu,name:menu_model_data_form"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
 msgctxt "model:ir.ui.menu,name:menu_model_field_access_form"
 msgid "Fields Access"
-msgstr ""
+msgstr "数据权限"
 
 msgctxt "model:ir.ui.menu,name:menu_model_form"
 msgid "Models"
-msgstr "Modellen"
+msgstr "模型"
 
 msgctxt "model:ir.ui.menu,name:menu_models"
 msgid "Models"
-msgstr "Modellen"
+msgstr "模型"
 
 msgctxt "model:ir.ui.menu,name:menu_module_form"
 msgid "Modules"
-msgstr "Modulen"
+msgstr "模块"
 
 msgctxt "model:ir.ui.menu,name:menu_module_install_upgrade"
 msgid "Perform Pending Installation/Upgrade"
-msgstr "Voer installatie / bijwerken uit"
+msgstr "执行未完成的”安装“ “升级”"
 
 msgctxt "model:ir.ui.menu,name:menu_modules"
 msgid "Modules"
-msgstr "Modulen"
+msgstr "模块"
+
+msgctxt "model:ir.ui.menu,name:menu_note_form"
+msgid "Notes"
+msgstr ""
 
 msgctxt "model:ir.ui.menu,name:menu_property_form"
 msgid "Properties"
-msgstr "Eigenschappen"
+msgstr "属性"
 
 msgctxt "model:ir.ui.menu,name:menu_property_form_default"
 msgid "Default Properties"
-msgstr "Standaard eigenschappen"
+msgstr "默认属性"
 
 msgctxt "model:ir.ui.menu,name:menu_rule_group_form"
 msgid "Record Rules"
-msgstr "Item regels"
+msgstr "数据规则"
 
 msgctxt "model:ir.ui.menu,name:menu_scheduler"
 msgid "Scheduler"
-msgstr "Planner"
+msgstr "计划"
 
 msgctxt "model:ir.ui.menu,name:menu_sequence_form"
 msgid "Sequences"
-msgstr "Reeksen"
+msgstr "序列"
 
 msgctxt "model:ir.ui.menu,name:menu_sequence_strict_form"
 msgid "Sequences Strict"
-msgstr "Vaste reeksen"
+msgstr "严格序列"
 
 msgctxt "model:ir.ui.menu,name:menu_sequences"
 msgid "Sequences"
-msgstr "Reeksen"
+msgstr "序列"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_clean"
 msgid "Clean Translations"
-msgstr "Vertalingen opschonen"
+msgstr "清理翻译"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_export"
 msgid "Export Translations"
-msgstr "Vertalingen exporteren"
+msgstr "导出翻译条目"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_form"
 msgid "Translations"
-msgstr "Vertalingen"
+msgstr "翻译"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_set"
 msgid "Set Translations"
-msgstr ""
+msgstr "保存翻译"
 
 msgctxt "model:ir.ui.menu,name:menu_translation_update"
 msgid "Synchronize Translations"
-msgstr "Vertaling synchroniseren"
+msgstr "使翻译生效"
 
 msgctxt "model:ir.ui.menu,name:menu_trigger_form"
 msgid "Triggers"
-msgstr "Starters"
+msgstr "触发器"
 
 msgctxt "model:ir.ui.menu,name:menu_ui"
 msgid "User Interface"
-msgstr "Gebruikers omgeving"
+msgstr "界面"
 
 msgctxt "model:ir.ui.menu,name:menu_view"
 msgid "Views"
-msgstr "Aanzichten"
+msgstr "视图"
 
 msgctxt "model:ir.ui.menu,name:menu_view_search"
 msgid "View Search"
-msgstr ""
+msgstr "搜索视图"
 
 msgctxt "model:ir.ui.menu,name:menu_view_tree_state"
 msgid "Tree State"
-msgstr ""
+msgstr "导航树状态"
 
 msgctxt "model:ir.ui.menu,name:menu_view_tree_width"
 msgid "View Tree Width"
-msgstr "Aanzicht boomstructuurbreedte"
+msgstr "导航树宽度"
 
 msgctxt "model:ir.ui.menu,name:model_model_fields_form"
 msgid "Fields"
-msgstr "Velden"
+msgstr "数据"
 
 msgctxt "model:ir.ui.menu.favorite,name:"
 msgid "Menu Favorite"
-msgstr ""
+msgstr "收藏"
 
 msgctxt "model:ir.ui.view,name:"
 msgid "View"
-msgstr "Overzicht"
+msgstr "视图"
 
 msgctxt "model:ir.ui.view.show.start,name:"
 msgid "Show view"
-msgstr ""
+msgstr "显示视图"
 
 msgctxt "model:ir.ui.view_search,name:"
 msgid "View Search"
-msgstr ""
+msgstr "搜索视图"
 
 msgctxt "model:ir.ui.view_tree_state,name:"
 msgid "View Tree State"
-msgstr ""
+msgstr "导航树状态"
 
 msgctxt "model:ir.ui.view_tree_width,name:"
 msgid "View Tree Width"
-msgstr "Aanzicht boomstructuurbreedte"
+msgstr "导航树宽度"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Action form"
-msgstr "Actieformulier"
+msgstr "动作表单"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Action tree"
-msgstr "Actie boomstructuur"
+msgstr "动作树形列表"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Form relate"
-msgstr "Formulier relatie"
+msgstr "表单关联"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Open Graph"
-msgstr "Open een grafiek"
+msgstr "打开表单"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Open tree"
-msgstr "Open boomstructuur"
+msgstr "打开树形列表"
 
 msgctxt "selection:ir.action.keyword,keyword:"
 msgid "Print form"
-msgstr "Formulier afdrukken"
+msgstr "打印表单"
 
 msgctxt "selection:ir.attachment,type:"
 msgid "Data"
-msgstr ""
+msgstr "数据"
 
-#, fuzzy
 msgctxt "selection:ir.attachment,type:"
 msgid "Link"
-msgstr "Verbinding"
+msgstr "链接"
 
 msgctxt "selection:ir.cron,interval_type:"
 msgid "Days"
-msgstr "Dagen"
+msgstr "日"
 
 msgctxt "selection:ir.cron,interval_type:"
 msgid "Hours"
-msgstr "Uren"
+msgstr "小时"
 
 msgctxt "selection:ir.cron,interval_type:"
 msgid "Minutes"
-msgstr "Minuten"
+msgstr "分钟"
 
 msgctxt "selection:ir.cron,interval_type:"
 msgid "Months"
-msgstr "Maanden"
+msgstr "月"
 
 msgctxt "selection:ir.cron,interval_type:"
 msgid "Weeks"
-msgstr "Weken"
+msgstr "周"
 
 msgctxt "selection:ir.lang,direction:"
 msgid "Left-to-right"
-msgstr "Van links naar rechts"
+msgstr "从左向右"
 
 msgctxt "selection:ir.lang,direction:"
 msgid "Right-to-left"
-msgstr "Van rechts naar links"
+msgstr "从右向左"
 
 msgctxt "selection:ir.module,state:"
 msgid "Installed"
-msgstr ""
+msgstr "已安装"
 
 msgctxt "selection:ir.module,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "未安装"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "待安装"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "待删除"
 
 msgctxt "selection:ir.module,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "待升级"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Done"
-msgstr ""
+msgstr "完成"
 
 msgctxt "selection:ir.module.config_wizard.item,state:"
 msgid "Open"
-msgstr ""
+msgstr "打开"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Installed"
-msgstr ""
+msgstr "已安装"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Not Installed"
-msgstr ""
+msgstr "未安装"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be installed"
-msgstr ""
+msgstr "待安装"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be removed"
-msgstr ""
+msgstr "待删除"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "To be upgraded"
-msgstr ""
+msgstr "待升级"
 
 msgctxt "selection:ir.module.dependency,state:"
 msgid "Unknown"
-msgstr ""
+msgstr "未知"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Decimal Timestamp"
-msgstr "Tijdmarkering"
+msgstr "十进制时间戳"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Hexadecimal Timestamp"
-msgstr "Hexadecimale tijdmarkering"
+msgstr "十六进制时间戳"
 
 msgctxt "selection:ir.sequence,type:"
 msgid "Incremental"
-msgstr "Oplopend"
+msgstr "升序"
 
 msgctxt "selection:ir.sequence.strict,type:"
 msgid "Decimal Timestamp"
-msgstr "Tijdmarkering"
+msgstr "十进制时间戳"
 
 msgctxt "selection:ir.sequence.strict,type:"
 msgid "Hexadecimal Timestamp"
-msgstr "Hexadecimale tijdmarkering"
+msgstr "十六进制时间戳"
 
 msgctxt "selection:ir.sequence.strict,type:"
 msgid "Incremental"
-msgstr "Oplopend"
+msgstr "升序"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Error"
-msgstr "Fout"
+msgstr "错误"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Field"
-msgstr "Veld"
+msgstr "数据"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Help"
-msgstr "Help"
+msgstr "帮助"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Model"
-msgstr "Model"
+msgstr "模型"
 
+#, fuzzy
 msgctxt "selection:ir.translation,type:"
-msgid "ODT"
-msgstr "ODT"
+msgid "Report"
+msgstr "报告..."
 
 msgctxt "selection:ir.translation,type:"
 msgid "Selection"
-msgstr "Selectie"
+msgstr "选择"
 
 msgctxt "selection:ir.translation,type:"
 msgid "View"
-msgstr "Aanzicht"
+msgstr "视图"
 
 msgctxt "selection:ir.translation,type:"
 msgid "Wizard Button"
-msgstr "Assistent knop"
+msgstr "向导按钮"
 
 msgctxt "selection:ir.ui.menu,action:"
 msgid ""
@@ -3620,80 +3672,75 @@ msgstr ""
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Board"
-msgstr "Bord"
+msgstr "板块"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Calendar"
-msgstr ""
+msgstr "日历"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Form"
-msgstr "Formulier"
+msgstr "表单"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Graph"
-msgstr "Grafiek"
+msgstr "图标"
 
 msgctxt "selection:ir.ui.view,type:"
 msgid "Tree"
-msgstr "Boomstructuur"
+msgstr "树形"
 
-#, fuzzy
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domain"
-msgstr "Domein"
+msgstr "域配置"
 
 msgctxt "view:ir.action.act_window.domain:"
 msgid "Domains"
-msgstr ""
+msgstr "域配置"
 
-#, fuzzy
 msgctxt "view:ir.action.act_window.view:"
 msgid "View"
-msgstr "Overzicht"
+msgstr "视图"
 
-#, fuzzy
 msgctxt "view:ir.action.act_window.view:"
 msgid "Views"
-msgstr "Aanzichten"
+msgstr "视图"
 
 msgctxt "view:ir.action.act_window:"
 msgid "General"
-msgstr "Algemeen"
+msgstr "基本"
 
 msgctxt "view:ir.action.act_window:"
 msgid "Open Window"
-msgstr "Open scherm"
+msgstr "打开窗口"
 
 msgctxt "view:ir.action.act_window:"
 msgid "Open a Window"
-msgstr "Open een scherm"
+msgstr "打开窗口"
 
-#, fuzzy
 msgctxt "view:ir.action.keyword:"
 msgid "Keyword"
-msgstr "Trefwoord"
+msgstr "关键词"
 
-#, fuzzy
 msgctxt "view:ir.action.keyword:"
 msgid "Keywords"
-msgstr "Trefwoorden"
+msgstr "关键词"
 
 msgctxt "view:ir.action.report:"
 msgid "General"
-msgstr "Algemeen"
+msgstr "基本"
 
 msgctxt "view:ir.action.report:"
 msgid "Report"
-msgstr "Verslag"
+msgstr "报告..."
 
 msgctxt "view:ir.action.report:"
 msgid "Report xml"
-msgstr "Rapportage xml"
+msgstr "报表xml"
 
 msgctxt "view:ir.action.url:"
 msgid "General"
-msgstr "Algemeen"
+msgstr "基本"
 
 msgctxt "view:ir.action.url:"
 msgid "URL"
@@ -3701,464 +3748,473 @@ msgstr "URL"
 
 msgctxt "view:ir.action.wizard:"
 msgid "General"
-msgstr "Algemeen"
+msgstr "基本"
 
 msgctxt "view:ir.action.wizard:"
 msgid "Wizard"
-msgstr "Assistent"
+msgstr "向导"
 
 msgctxt "view:ir.action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "操作"
 
 msgctxt "view:ir.action:"
 msgid "General"
-msgstr "Algemeen"
+msgstr "基本"
 
 msgctxt "view:ir.attachment:"
 msgid "Attachments"
-msgstr "Bijlagen"
+msgstr "附件文档"
 
 msgctxt "view:ir.attachment:"
 msgid "Last Modification Time"
-msgstr ""
+msgstr "最近更改时间"
 
 msgctxt "view:ir.cron:"
 msgid "Action to trigger"
-msgstr "Actie om uit te voeren"
+msgstr "待执行"
+
+msgctxt "view:ir.cron:"
+msgid "Run Once"
+msgstr ""
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Action"
-msgstr "Geplande actie"
+msgstr "计划动作"
 
 msgctxt "view:ir.cron:"
 msgid "Scheduled Actions"
-msgstr "Geplande acties"
+msgstr "计划动作"
 
 msgctxt "view:ir.export:"
 msgid "Exports"
-msgstr "Export"
+msgstr "导出"
 
 msgctxt "view:ir.lang:"
 msgid "Date Formatting"
-msgstr "Datum format"
+msgstr "日期格式"
 
 msgctxt "view:ir.lang:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
 msgctxt "view:ir.lang:"
 msgid "Languages"
-msgstr "Talen"
+msgstr "语言"
 
 msgctxt "view:ir.lang:"
 msgid "Numbers Formatting"
-msgstr "Getal weergave"
+msgstr "数字书写格式"
 
 msgctxt "view:ir.model.access:"
 msgid "Access controls"
-msgstr "Toegangcontrole"
+msgstr "权限控制"
 
 msgctxt "view:ir.model.button:"
 msgid "Button"
-msgstr ""
+msgstr "按钮"
 
 msgctxt "view:ir.model.button:"
 msgid "Buttons"
-msgstr ""
+msgstr "按钮"
 
 msgctxt "view:ir.model.data:"
 msgid "Model Data"
-msgstr ""
+msgstr "模型数据"
 
 msgctxt "view:ir.model.data:"
 msgid "Sync"
-msgstr ""
+msgstr "同步"
 
 msgctxt "view:ir.model.field.access:"
 msgid "Field Access"
-msgstr ""
+msgstr "数据权限"
 
-#, fuzzy
 msgctxt "view:ir.model.field:"
 msgid "Field"
-msgstr "Veld"
+msgstr "数据"
 
 msgctxt "view:ir.model.field:"
 msgid "Fields"
-msgstr "Velden"
+msgstr "数据"
 
 msgctxt "view:ir.model.print_model_graph.start:"
 msgid "Print Model Graph"
-msgstr ""
+msgstr "打印模型图表"
 
 msgctxt "view:ir.model:"
 msgid "Model Description"
-msgstr "Model omschrijving"
+msgstr "模型描述"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "Module configuration"
-msgstr ""
+msgstr "模块设置"
 
 msgctxt "view:ir.module.config_wizard.done:"
 msgid "The configuration is done."
-msgstr ""
+msgstr "设置结束."
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid "Welcome to the module configuration wizard!"
-msgstr ""
+msgstr "欢迎使用模块设置向导!"
 
 msgctxt "view:ir.module.config_wizard.first:"
 msgid ""
 "You will be able to configure your installation depending on the modules you"
 " have installed."
-msgstr ""
+msgstr "通过本向导可以对安装的模块进行设置."
 
 msgctxt "view:ir.module.config_wizard.item:"
 msgid "Config Wizard Items"
-msgstr ""
+msgstr "设置向导项目"
 
 msgctxt "view:ir.module.config_wizard.other:"
 msgid "Configuration Wizard Next Step!"
-msgstr ""
+msgstr "设置向导下一步!"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependencies"
-msgstr ""
+msgstr "依赖"
 
 msgctxt "view:ir.module.dependency:"
 msgid "Dependency"
-msgstr ""
+msgstr "模块依赖关系"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "System Upgrade Done"
-msgstr ""
+msgstr "系统升级完成"
 
 msgctxt "view:ir.module.install_upgrade.done:"
 msgid "The modules have been upgraded / installed !"
-msgstr ""
+msgstr "所选模块升级/安装成功 !"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Note that this operation may take a few minutes."
-msgstr ""
+msgstr "完成本操作可能会花费一些时间."
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "System Upgrade"
-msgstr ""
+msgstr "系统升级"
 
 msgctxt "view:ir.module.install_upgrade.start:"
 msgid "Your system will be upgraded."
-msgstr ""
+msgstr "将进行系统升级."
 
 msgctxt "view:ir.module:"
 msgid "Cancel Installation"
-msgstr ""
+msgstr "取消“安装”"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Uninstallation"
-msgstr ""
+msgstr "取消“卸载”"
 
 msgctxt "view:ir.module:"
 msgid "Cancel Upgrade"
-msgstr ""
+msgstr "取消“升级”"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Installation"
-msgstr ""
+msgstr "标记“安装”"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Uninstallation (beta)"
-msgstr ""
+msgstr "标记“卸载”"
 
 msgctxt "view:ir.module:"
 msgid "Mark for Upgrade"
-msgstr ""
+msgstr "标记“升级”"
 
 msgctxt "view:ir.module:"
 msgid "Module"
-msgstr ""
+msgstr "模块"
 
 msgctxt "view:ir.module:"
 msgid "Modules"
+msgstr "模块"
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "Date"
+msgstr "日期格式"
+
+msgctxt "view:ir.note:"
+msgid "Note"
 msgstr ""
 
+msgctxt "view:ir.note:"
+msgid "Notes"
+msgstr ""
+
+msgctxt "view:ir.note:"
+msgid "Time"
+msgstr ""
+
+#, fuzzy
+msgctxt "view:ir.note:"
+msgid "User"
+msgstr "用户"
+
 msgctxt "view:ir.property:"
 msgid "Properties"
-msgstr "Eigenschappen"
+msgstr "属性"
 
 msgctxt "view:ir.property:"
 msgid "Property"
-msgstr "Eigenschap"
+msgstr "属性"
 
 msgctxt "view:ir.rule.group:"
 msgid ""
 "If there is no test defined, the rule is always satisfied if not global"
-msgstr ""
-"Als er geen test is gedefinieerd is de regel altijd waar mits niet globaal"
+msgstr "非全局规则有明确的测试定义才有效."
 
 msgctxt "view:ir.rule.group:"
 msgid "Record rules"
-msgstr "Item regels"
+msgstr "数据规则"
 
 msgctxt "view:ir.rule.group:"
 msgid "The rule is satisfied if at least one test is True"
-msgstr "De regel is waar als tenminste aan één voorwaarde wordt voldaan"
+msgstr "任意一项测试结果为真,即判断符合规则."
 
 msgctxt "view:ir.rule:"
 msgid "Test"
-msgstr "Test"
+msgstr "测试"
 
 msgctxt "view:ir.sequence.type:"
 msgid "Sequence Type"
-msgstr "Reeks type"
+msgstr "序列类型"
 
 msgctxt "view:ir.sequence:"
 msgid "${day}"
-msgstr "${dag}"
+msgstr "${day}"
 
 msgctxt "view:ir.sequence:"
 msgid "${month}"
-msgstr "${maand}"
+msgstr "${month}"
 
 msgctxt "view:ir.sequence:"
 msgid "${year}"
-msgstr "${jaar}"
+msgstr "${year}"
 
 msgctxt "view:ir.sequence:"
 msgid "Day:"
-msgstr "Dag:"
+msgstr "日"
 
 msgctxt "view:ir.sequence:"
 msgid "Incremental"
-msgstr "Oplopend"
+msgstr "升序"
 
 msgctxt "view:ir.sequence:"
 msgid "Legend (Placeholders for prefix, suffix)"
-msgstr "Legenda (sjabloon voor voorvoegsel, toevoeging)"
+msgstr "前后缀占位符"
 
 msgctxt "view:ir.sequence:"
 msgid "Month:"
-msgstr "Maand:"
+msgstr "月份:"
 
 msgctxt "view:ir.sequence:"
 msgid "Sequences"
-msgstr "Reeksen"
+msgstr "序列"
 
 msgctxt "view:ir.sequence:"
 msgid "Timestamp"
-msgstr "Tijdmarkering"
+msgstr "时间戳"
 
 msgctxt "view:ir.sequence:"
 msgid "Year:"
-msgstr "Jaar:"
+msgstr "年份"
 
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations"
-msgstr "Vertalingen opschonen"
+msgstr "清理翻译"
 
 msgctxt "view:ir.translation.clean.start:"
 msgid "Clean Translations?"
-msgstr ""
+msgstr "清理翻译 ?"
 
-#, fuzzy
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations"
-msgstr "Vertalingen opschonen"
+msgstr "清理翻译"
 
-#, fuzzy
 msgctxt "view:ir.translation.clean.succeed:"
 msgid "Clean Translations Succeed!"
-msgstr "Vertalingen opschonen gelukt!"
+msgstr "翻译清理成功!"
 
-#, fuzzy
 msgctxt "view:ir.translation.export.result:"
 msgid "Export Translation"
-msgstr "Vertaling exporteren"
+msgstr "导出翻译条目"
 
 msgctxt "view:ir.translation.export.start:"
 msgid "Export Translation"
-msgstr "Vertaling exporteren"
+msgstr "导出翻译条目"
 
 msgctxt "view:ir.translation.set.start:"
 msgid "Set Translations"
-msgstr ""
+msgstr "保存翻译"
 
 msgctxt "view:ir.translation.set.start:"
 msgid "Synchronize Translations?"
-msgstr ""
+msgstr "使翻译生效?"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Succeed!"
-msgstr ""
+msgstr "保存成功!"
 
 msgctxt "view:ir.translation.set.succeed:"
 msgid "Set Translations"
-msgstr ""
+msgstr "保存翻译"
 
-#, fuzzy
 msgctxt "view:ir.translation.update.start:"
 msgid "Synchronize Translations"
-msgstr "Vertaling synchroniseren"
+msgstr "使翻译生效"
 
 msgctxt "view:ir.translation:"
 msgid "Translations"
-msgstr "Vertalingen"
+msgstr "翻译"
 
 msgctxt "view:ir.trigger:"
 msgid "Trigger"
-msgstr "Starter"
+msgstr "触发器"
 
 msgctxt "view:ir.trigger:"
 msgid "Triggers"
-msgstr "Starters"
+msgstr "触发器"
 
-#, fuzzy
 msgctxt "view:ir.ui.icon:"
 msgid "Icon"
-msgstr "Icoon"
+msgstr "图标"
 
 msgctxt "view:ir.ui.icon:"
 msgid "Icons"
-msgstr ""
+msgstr "图标"
 
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorite"
-msgstr ""
+msgstr "收藏"
 
 msgctxt "view:ir.ui.menu.favorite:"
 msgid "Menu Favorites"
-msgstr ""
+msgstr "收藏"
 
 msgctxt "view:ir.ui.menu:"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
 msgctxt "view:ir.ui.view:"
 msgid "Show"
-msgstr ""
+msgstr "显示"
 
 msgctxt "view:ir.ui.view:"
 msgid "View"
-msgstr "Overzicht"
+msgstr "视图"
 
 msgctxt "view:ir.ui.view_search:"
 msgid "View Search"
-msgstr ""
+msgstr "搜索视图"
 
 msgctxt "view:ir.ui.view_search:"
 msgid "View Searches"
-msgstr ""
+msgstr "搜索视图"
 
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "View Tree State"
-msgstr ""
+msgstr "导航树状态"
 
 msgctxt "view:ir.ui.view_tree_state:"
 msgid "Views Tree State"
-msgstr ""
+msgstr "导航树状态"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "View Tree Width"
-msgstr "Aanzicht boomstructuurbreedte"
+msgstr "导航树宽度"
 
 msgctxt "view:ir.ui.view_tree_width:"
 msgid "Views Tree Width"
-msgstr "Aanzichten boomstructuurbreedte"
+msgstr "导航树宽度"
 
-#, fuzzy
 msgctxt "wizard_button:ir.model.print_model_graph,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
 msgctxt "wizard_button:ir.model.print_model_graph,start,print_:"
 msgid "Print"
-msgstr ""
+msgstr "打印"
 
 msgctxt "wizard_button:ir.module.config_wizard,done,end:"
 msgid "OK"
-msgstr ""
+msgstr "确定"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,action:"
 msgid "OK"
-msgstr ""
+msgstr "确定"
 
 msgctxt "wizard_button:ir.module.config_wizard,first,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "取消"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,action:"
 msgid "Next"
-msgstr ""
+msgstr "下一步"
 
 msgctxt "wizard_button:ir.module.config_wizard,other,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "取消"
 
 msgctxt "wizard_button:ir.module.install_upgrade,done,config:"
 msgid "OK"
-msgstr ""
+msgstr "确定"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,end:"
 msgid "Cancel"
-msgstr ""
+msgstr "取消"
 
 msgctxt "wizard_button:ir.module.install_upgrade,start,upgrade:"
 msgid "Start Upgrade"
-msgstr ""
+msgstr "升级"
 
 msgctxt "wizard_button:ir.translation.clean,start,clean:"
 msgid "Clean"
-msgstr ""
+msgstr "清理"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.clean,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.clean,succeed,end:"
 msgid "OK"
-msgstr "Oké"
+msgstr "确定"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.export,result,end:"
 msgid "Close"
-msgstr "Sluiten"
+msgstr "关闭"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.export,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.export,start,export:"
 msgid "Export"
-msgstr "Exporteren"
+msgstr "导出"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.set,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
 msgctxt "wizard_button:ir.translation.set,start,set_:"
 msgid "Set"
-msgstr ""
+msgstr "设置"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.set,succeed,end:"
 msgid "OK"
-msgstr "Oké"
+msgstr "确定"
 
-#, fuzzy
 msgctxt "wizard_button:ir.translation.update,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
 msgctxt "wizard_button:ir.translation.update,start,update:"
 msgid "Update"
-msgstr ""
+msgstr "更新"
 
-#, fuzzy
 msgctxt "wizard_button:ir.ui.view.show,start,end:"
 msgid "Close"
-msgstr "Sluiten"
+msgstr "关闭"
diff --git a/trytond/ir/model.py b/trytond/ir/model.py
index 01e0b11..9045980 100644
--- a/trytond/ir/model.py
+++ b/trytond/ir/model.py
@@ -12,7 +12,7 @@ try:
 except ImportError:
     import json
 
-from ..model import ModelView, ModelSQL, fields, Unique
+from ..model import ModelView, ModelSQL, Workflow, fields, Unique
 from ..report import Report
 from ..wizard import Wizard, StateView, StateAction, Button
 from ..transaction import Transaction
@@ -22,7 +22,7 @@ from ..pyson import Bool, Eval
 from ..rpc import RPC
 from .. import backend
 from ..protocols.jsonrpc import JSONDecoder, JSONEncoder
-from ..tools import is_instance_method
+from ..tools import is_instance_method, cursor_dict
 try:
     from ..tools.StringMatcher import StringMatcher
 except ImportError:
@@ -31,6 +31,7 @@ except ImportError:
 __all__ = [
     'Model', 'ModelField', 'ModelAccess', 'ModelFieldAccess', 'ModelButton',
     'ModelData', 'PrintModelGraphStart', 'PrintModelGraph', 'ModelGraph',
+    'ModelWorkflowGraph',
     ]
 
 IDENTIFIER = re.compile(r'^[a-zA-z_][a-zA-Z0-9_]*$')
@@ -84,7 +85,7 @@ class Model(ModelSQL, ModelView):
     def register(cls, model, module_name):
         pool = Pool()
         Property = pool.get('ir.property')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         ir_model = cls.__table__()
         cursor.execute(*ir_model.select(ir_model.id,
@@ -265,7 +266,7 @@ class ModelField(ModelSQL, ModelView):
     def register(cls, model, module_name, model_id):
         pool = Pool()
         Model = pool.get('ir.model')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         ir_model_field = cls.__table__()
         ir_model = Model.__table__()
@@ -280,7 +281,7 @@ class ModelField(ModelSQL, ModelView):
                 ir_model_field.module.as_('module'),
                 ir_model_field.help.as_('help'),
                 where=ir_model.model == model.__name__))
-        model_fields = dict((f['name'], f) for f in cursor.dictfetchall())
+        model_fields = {f['name']: f for f in cursor_dict(cursor)}
 
         for field_name, field in model._fields.iteritems():
             if hasattr(field, 'model_name'):
@@ -374,7 +375,7 @@ class ModelField(ModelSQL, ModelView):
                 else:
                     model_ids.add(rec['model'])
             model_ids = list(model_ids)
-            cursor = Transaction().cursor
+            cursor = Transaction().connection.cursor()
             model = Model.__table__()
             cursor.execute(*model.select(model.id, model.model,
                     where=model.id.in_(model_ids)))
@@ -449,11 +450,10 @@ class ModelAccess(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
 
         super(ModelAccess, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.6 (model, group) no more unique
         table.drop_constraint('model_group_uniq')
@@ -488,7 +488,7 @@ class ModelAccess(ModelSQL, ModelView):
         pool = Pool()
         Model = pool.get('ir.model')
         UserGroup = pool.get('res.user-res.group')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         user = Transaction().user
         model_access = cls.__table__()
         ir_model = Model.__table__()
@@ -628,11 +628,10 @@ class ModelFieldAccess(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
 
         super(ModelFieldAccess, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.6 (field, group) no more unique
         table.drop_constraint('field_group_uniq')
@@ -669,7 +668,6 @@ class ModelFieldAccess(ModelSQL, ModelView):
         Model = pool.get('ir.model')
         ModelField = pool.get('ir.model.field')
         UserGroup = pool.get('res.user-res.group')
-        cursor = Transaction().cursor
         user = Transaction().user
         field_access = cls.__table__()
         ir_model = Model.__table__()
@@ -687,6 +685,7 @@ class ModelFieldAccess(ModelSQL, ModelView):
 
         default = {}
         accesses = dict((m, default) for m in models)
+        cursor = Transaction().connection.cursor()
         cursor.execute(*field_access.join(model_field,
                 condition=field_access.field == model_field.id
                 ).join(ir_model,
@@ -856,12 +855,12 @@ class ModelData(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         model_data = cls.__table__()
 
         super(ModelData, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.6: remove inherit
         if table.column_exist('inherit'):
@@ -1097,3 +1096,58 @@ class ModelGraph(Report):
 
                     edge = pydot.Edge(str(tail), str(head), **args)
                     graph.add_edge(edge)
+
+
+class ModelWorkflowGraph(Report):
+    __name__ = 'ir.model.workflow_graph'
+
+    @classmethod
+    def execute(cls, ids, data):
+        import pydot
+        pool = Pool()
+        Model = pool.get('ir.model')
+        ActionReport = pool.get('ir.action.report')
+
+        action_report_ids = ActionReport.search([
+            ('report_name', '=', cls.__name__)
+            ])
+        if not action_report_ids:
+            raise Exception('Error', 'Report (%s) not find!' % cls.__name__)
+        action_report = ActionReport(action_report_ids[0])
+
+        models = Model.browse(ids)
+
+        graph = pydot.Dot()
+        graph.set('center', '1')
+        graph.set('ratio', 'auto')
+        direction = Transaction().context.get('language_direction', 'ltr')
+        graph.set('rankdir', {'ltr': 'LR', 'rtl': 'RL'}[direction])
+        cls.fill_graph(models, graph)
+        data = graph.create(prog='dot', format='png')
+        return ('png', fields.Binary.cast(data), False, action_report.name)
+
+    @classmethod
+    def fill_graph(cls, models, graph):
+        'Fills pydot graph with models wizard.'
+        import pydot
+        pool = Pool()
+
+        for record in models:
+            Model = pool.get(record.model)
+
+            if not issubclass(Model, Workflow):
+                continue
+
+            subgraph = pydot.Cluster('%s' % record.id, label=record.model)
+            graph.add_subgraph(subgraph)
+
+            state_field = getattr(Model, Model._transition_state)
+            for state, _ in state_field.selection:
+                node = pydot.Node(
+                    '"%s"' % state, shape='octagon', label=state)
+                subgraph.add_node(node)
+
+            for from_, to in Model._transitions:
+                edge = pydot.Edge('"%s"' % from_, '"%s"' % to,
+                    arrowhead='normal')
+                subgraph.add_edge(edge)
diff --git a/trytond/ir/model.xml b/trytond/ir/model.xml
index ae4d69d..4983161 100644
--- a/trytond/ir/model.xml
+++ b/trytond/ir/model.xml
@@ -143,6 +143,18 @@ this repository contains the full copyright notices and license terms. -->
             <field name="action" ref="print_model_graph"/>
         </record>
 
+        <record model="ir.action.report" id="report_model_workflow_graph">
+            <field name="name">Workflow Graph</field>
+            <field name="model">ir.model</field>
+            <field name="report_name">ir.model.workflow_graph</field>
+        </record>
+        <record model="ir.action.keyword"
+            id="print_model_workflow_graph_keyword">
+            <field name="keyword">form_print</field>
+            <field name="model">ir.model,-1</field>
+            <field name="action" ref="report_model_workflow_graph"/>
+        </record>
+
         <record model="ir.ui.view" id="model_button_view_list">
             <field name="model">ir.model.button</field>
             <field name="type">tree</field>
diff --git a/trytond/ir/module.py b/trytond/ir/module.py
index d2312f2..1514a1b 100644
--- a/trytond/ir/module.py
+++ b/trytond/ir/module.py
@@ -97,12 +97,11 @@ class Module(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
 
         # Migration from 3.6: remove double module
         old_table = 'ir_module_module'
-        if TableHandler.table_exist(cursor, old_table):
-            TableHandler.table_rename(cursor, old_table, cls._table)
+        if TableHandler.table_exist(old_table):
+            TableHandler.table_rename(old_table, cls._table)
 
         super(Module, cls).__register__(module_name)
 
@@ -241,7 +240,7 @@ class Module(ModelSQL, ModelView):
         Dependency = pool.get('ir.module.dependency')
         module_table = Module.__table__()
         dep_table = Dependency.__table__()
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         for module in modules:
             cursor.execute(*dep_table.join(module_table,
                     condition=(dep_table.module == module_table.id)
@@ -344,12 +343,11 @@ class ModuleDependency(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
 
         # Migration from 3.6: remove double module
         old_table = 'ir_module_module_dependency'
-        if TableHandler.table_exist(cursor, old_table):
-            TableHandler.table_rename(cursor, old_table, cls._table)
+        if TableHandler.table_exist(old_table):
+            TableHandler.table_rename(old_table, cls._table)
 
         super(ModuleDependency, cls).__register__(module_name)
 
@@ -385,22 +383,22 @@ class ModuleConfigWizardItem(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         pool = Pool()
         ModelData = pool.get('ir.model.data')
         model_data = ModelData.__table__()
 
         # Migration from 3.6: remove double module
         old_table = 'ir_module_module_config_wizard_item'
-        if TableHandler.table_exist(cursor, old_table):
-            TableHandler.table_rename(cursor, old_table, cls._table)
+        if TableHandler.table_exist(old_table):
+            TableHandler.table_rename(old_table, cls._table)
         cursor.execute(*model_data.update(
                 columns=[model_data.model],
                 values=[cls.__name__],
                 where=(model_data.model ==
                     'ir.module.module.config_wizard.item')))
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migrate from 2.2 remove name
         table.drop_column('name')
@@ -481,7 +479,7 @@ class ModuleConfigWizard(Wizard):
     action = ConfigStateAction()
     done = StateView('ir.module.config_wizard.done',
         'ir.module_config_wizard_done_view_form', [
-            Button('OK', 'end', 'tryton-close', default=True),
+            Button('OK', 'end', 'tryton-ok', default=True),
             ])
 
     def transition_start(self):
@@ -533,8 +531,8 @@ class ModuleInstallUpgrade(Wizard):
 
     @classmethod
     def check_access(cls):
-        # Use new cursor to prevent lock when installing modules
-        with Transaction().new_cursor():
+        # Use new transaction to prevent lock when installing modules
+        with Transaction().new_transaction():
             super(ModuleInstallUpgrade, cls).check_access()
 
     @staticmethod
@@ -559,7 +557,7 @@ class ModuleInstallUpgrade(Wizard):
         pool = Pool()
         Module = pool.get('ir.module')
         Lang = pool.get('ir.lang')
-        with Transaction().new_cursor() as transaction:
+        with Transaction().new_transaction():
             modules = Module.search([
                 ('state', 'in', ['to upgrade', 'to remove', 'to install']),
                 ])
@@ -568,7 +566,6 @@ class ModuleInstallUpgrade(Wizard):
                 ('translatable', '=', True),
                 ])
             lang = [x.code for x in langs]
-            transaction.cursor.commit()
         if update:
             pool.init(update=update, lang=lang)
         return 'done'
diff --git a/trytond/ir/note.py b/trytond/ir/note.py
new file mode 100644
index 0000000..7a8c33a
--- /dev/null
+++ b/trytond/ir/note.py
@@ -0,0 +1,116 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from textwrap import TextWrapper
+
+from sql import Null
+from sql.conditionals import Case
+
+from ..model import ModelView, ModelSQL, ModelStorage, fields
+from ..pool import Pool
+from ..transaction import Transaction
+from ..tools import grouped_slice, reduce_ids
+from ..pyson import Eval
+from .resource import ResourceMixin
+
+__all__ = ['Note', 'NoteRead']
+
+
+class Note(ResourceMixin, ModelSQL, ModelView):
+    "Note"
+    __name__ = 'ir.note'
+    message = fields.Text('Message', states={
+            'readonly': Eval('id', 0) > 0,
+            })
+    message_wrapped = fields.Function(fields.Text('Message'),
+        'on_change_with_message_wrapped')
+    unread = fields.Function(fields.Boolean('Unread'), 'get_unread',
+        searcher='search_unread', setter='set_unread')
+
+    @staticmethod
+    def default_unread():
+        return False
+
+    @classmethod
+    def get_wrapper(cls):
+        return TextWrapper(width=79)
+
+    @fields.depends('message')
+    def on_change_with_message_wrapped(self, name=None):
+        wrapper = self.get_wrapper()
+        return '\n'.join(map(wrapper.fill, self.message.splitlines()))
+
+    @classmethod
+    def get_unread(cls, ids, name):
+        pool = Pool()
+        Read = pool.get('ir.note.read')
+        cursor = Transaction().connection.cursor()
+        user_id = Transaction().user
+        table = cls.__table__()
+        read = Read.__table__()
+
+        unread = {}
+        for sub_ids in grouped_slice(ids):
+            where = reduce_ids(table.id, sub_ids)
+            query = table.join(read, 'LEFT',
+                condition=(table.id == read.note)
+                & (read.user == user_id)
+                ).select(table.id,
+                    Case((read.user != Null, False), else_=True),
+                    where=where)
+            cursor.execute(*query)
+            unread.update(cursor.fetchall())
+        return unread
+
+    @classmethod
+    def search_unread(cls, name, clause):
+        pool = Pool()
+        Read = pool.get('ir.note.read')
+        user_id = Transaction().user
+        table = cls.__table__()
+        read = Read.__table__()
+
+        _, operator, value = clause
+        assert operator in ['=', '!=']
+        Operator = fields.SQL_OPERATORS[operator]
+
+        where = Operator(Case((read.user != Null, False), else_=True), value)
+        query = table.join(read, 'LEFT',
+            condition=(table.id == read.note)
+            & (read.user == user_id)
+            ).select(table.id, where=where)
+        return [('id', 'in', query)]
+
+    @classmethod
+    def set_unread(cls, notes, name, value):
+        pool = Pool()
+        Read = pool.get('ir.note.read')
+        user_id = Transaction().user
+        if not value:
+            Read.create([{'note': n.id, 'user': user_id} for n in notes])
+        else:
+            reads = []
+            for sub_notes in grouped_slice(notes):
+                reads += Read.search([
+                        ('note', 'in', [n.id for n in sub_notes]),
+                        ('user', '=', user_id),
+                        ])
+            Read.delete(reads)
+
+    @classmethod
+    def write(cls, notes, values, *args):
+        # Avoid changing write meta data if only unread is set
+        if args or values.keys() != ['unread']:
+            super(Note, cls).write(notes, values, *args)
+        else:
+            # Check access write and clean cache
+            ModelStorage.write(notes, values)
+            cls.set_unread(notes, 'unread', values['unread'])
+
+
+class NoteRead(ModelSQL):
+    "Note Read"
+    __name__ = 'ir.note.read'
+    note = fields.Many2One('ir.note', 'Note', required=True,
+        ondelete='CASCADE')
+    user = fields.Many2One('res.user', 'User', required=True,
+        ondelete='CASCADE')
diff --git a/trytond/ir/note.xml b/trytond/ir/note.xml
new file mode 100644
index 0000000..81d683f
--- /dev/null
+++ b/trytond/ir/note.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+    <data>
+        <record model="ir.ui.view" id="note_view_form">
+            <field name="model">ir.note</field>
+            <field name="type">form</field>
+            <field name="name">note_form</field>
+        </record>
+        <record model="ir.ui.view" id="note_view_list">
+            <field name="model">ir.note</field>
+            <field name="type">tree</field>
+            <field name="name">note_list</field>
+        </record>
+        <record model="ir.action.act_window" id="act_note_form">
+            <field name="name">Notes</field>
+            <field name="type">ir.action.act_window</field>
+            <field name="res_model">ir.note</field>
+        </record>
+        <record model="ir.action.act_window.view"
+            id="act_note_form_view1">
+            <field name="sequence" eval="1"/>
+            <field name="view" ref="note_view_list"/>
+            <field name="act_window" ref="act_note_form"/>
+        </record>
+        <record model="ir.action.act_window.view"
+            id="act_note_form_view2">
+            <field name="sequence" eval="2"/>
+            <field name="view" ref="note_view_form"/>
+            <field name="act_window" ref="act_note_form"/>
+        </record>
+        <menuitem parent="ir.menu_models" action="act_note_form"
+            id="menu_note_form"/>
+    </data>
+</tryton>
diff --git a/trytond/ir/property.py b/trytond/ir/property.py
index 9764b81..f4d0221 100644
--- a/trytond/ir/property.py
+++ b/trytond/ir/property.py
@@ -34,7 +34,7 @@ class Property(ModelSQL, ModelView):
         models = cls._models_get_cache.get(None)
         if models:
             return models
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         model = Model.__table__()
         cursor.execute(*model.select(model.model, model.name,
                 order_by=model.name.asc))
diff --git a/trytond/ir/resource.py b/trytond/ir/resource.py
new file mode 100644
index 0000000..0613592
--- /dev/null
+++ b/trytond/ir/resource.py
@@ -0,0 +1,113 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from sql.conditionals import Coalesce
+
+from ..model import ModelSQL, ModelView, fields
+from ..pool import Pool
+from ..transaction import Transaction
+from ..pyson import Eval
+
+__all__ = ['ResourceMixin']
+
+
+class ResourceMixin(ModelSQL, ModelView):
+
+    resource = fields.Reference('Resource', selection='get_models',
+        required=True, select=True)
+    last_user = fields.Function(fields.Char('Last User',
+            states={
+                'invisible': ~Eval('last_user'),
+                }),
+        'get_last_user')
+    last_modification = fields.Function(fields.DateTime('Last Modification',
+            states={
+                'invisible': ~Eval('last_modification'),
+                }),
+        'get_last_modification')
+
+    @classmethod
+    def __setup__(cls):
+        super(ResourceMixin, cls).__setup__()
+        cls._order.insert(0, ('last_modification', 'DESC'))
+
+    @staticmethod
+    def default_resource():
+        return Transaction().context.get('resource')
+
+    @staticmethod
+    def get_models():
+        pool = Pool()
+        Model = pool.get('ir.model')
+        ModelAccess = pool.get('ir.model.access')
+        models = Model.search([])
+        access = ModelAccess.get_access([m.model for m in models])
+        return [(m.model, m.name) for m in models if access[m.model]['read']]
+
+    def get_last_user(self, name):
+        return (self.write_uid.rec_name if self.write_uid
+            else self.create_uid.rec_name)
+
+    def get_last_modification(self, name):
+        return (self.write_date if self.write_date else self.create_date
+            ).replace(microsecond=0)
+
+    @staticmethod
+    def order_last_modification(tables):
+        table, _ = tables[None]
+        return [Coalesce(table.write_date, table.create_date)]
+
+    @classmethod
+    def check_access(cls, ids, mode='read'):
+        pool = Pool()
+        ModelAccess = pool.get('ir.model.access')
+        if ((Transaction().user == 0)
+                or not Transaction().context.get('_check_access')):
+            return
+        model_names = set()
+        with Transaction().set_context(_check_access=False):
+            for record in cls.browse(ids):
+                if record.resource:
+                    model_names.add(record.resource.__name__)
+        for model_name in model_names:
+            ModelAccess.check(model_name, mode=mode)
+
+    @classmethod
+    def read(cls, ids, fields_names=None):
+        cls.check_access(ids, mode='read')
+        return super(ResourceMixin, cls).read(ids, fields_names=fields_names)
+
+    @classmethod
+    def delete(cls, records):
+        cls.check_access([a.id for a in records], mode='delete')
+        super(ResourceMixin, cls).delete(records)
+
+    @classmethod
+    def write(cls, records, values, *args):
+        all_records = []
+        actions = iter((records, values) + args)
+        for other_records, _ in zip(actions, actions):
+            all_records += other_records
+        cls.check_access([a.id for a in all_records], mode='write')
+        super(ResourceMixin, cls).write(records, values, *args)
+        cls.check_access(all_records, mode='write')
+
+    @classmethod
+    def create(cls, vlist):
+        records = super(ResourceMixin, cls).create(vlist)
+        cls.check_access([r.id for r in records], mode='create')
+        return records
+
+    @classmethod
+    def view_header_get(cls, value, view_type='form'):
+        pool = Pool()
+        Model = pool.get('ir.model')
+        value = super(ResourceMixin, cls).view_header_get(
+            value, view_type=view_type)
+        resource = Transaction().context.get('resource')
+        if resource:
+            model_name, record_id = resource.split(',', 1)
+            model, = Model.search([('model', '=', model_name)])
+            Resource = pool.get(model_name)
+            record = Resource(int(record_id))
+            value = '%s - %s - %s' % (model.name, record.rec_name, value)
+        return value
diff --git a/trytond/ir/rule.py b/trytond/ir/rule.py
index f3dc849..e78e14a 100644
--- a/trytond/ir/rule.py
+++ b/trytond/ir/rule.py
@@ -113,7 +113,7 @@ class Rule(ModelSQL, ModelView):
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
         super(Rule, cls).__register__(module_name)
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.6: replace field, operator and operand by domain
         table.not_null_action('field', action='remove')
@@ -181,7 +181,7 @@ class Rule(ModelSQL, ModelView):
         RuleGroup_Group = pool.get('ir.rule.group-res.group')
         User_Group = pool.get('res.user-res.group')
 
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         rule_table = cls.__table__()
         rule_group = RuleGroup.__table__()
         rule_group_user = RuleGroup_User.__table__()
diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py
index f687760..19a0637 100644
--- a/trytond/ir/sequence.py
+++ b/trytond/ir/sequence.py
@@ -103,8 +103,7 @@ class Sequence(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.0 rename number_next into number_next_internal
         table.column_rename('number_next', 'number_next_internal')
@@ -117,7 +116,7 @@ class Sequence(ModelSQL, ModelView):
             for sequence in sequences:
                 if sequence.type != 'incremental':
                     continue
-                if not TableHandler.sequence_exist(cursor,
+                if not TableHandler.sequence_exist(
                         sequence._sql_sequence_name):
                     sequence.create_sql_sequence(sequence.number_next_internal)
 
@@ -158,7 +157,9 @@ class Sequence(ModelSQL, ModelView):
         return Transaction().context.get('code')
 
     def get_number_next(self, name):
-        cursor = Transaction().cursor
+        if self.type != 'incremental':
+            return
+        cursor = Transaction().connection.cursor()
         sql_name = self._sql_sequence_name
         if sql_sequence and not self._strict:
             cursor.execute('SELECT '
@@ -258,7 +259,7 @@ class Sequence(ModelSQL, ModelView):
 
     def create_sql_sequence(self, number_next=None):
         'Create the SQL sequence'
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         param = Flavor.get().param
         if self.type != 'incremental':
             return
@@ -271,9 +272,9 @@ class Sequence(ModelSQL, ModelView):
     def update_sql_sequence(self, number_next=None):
         'Update the SQL sequence'
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         param = Flavor.get().param
-        exist = TableHandler.sequence_exist(cursor, self._sql_sequence_name)
+        exist = TableHandler.sequence_exist(self._sql_sequence_name)
         if self.type != 'incremental':
             if exist:
                 self.delete_sql_sequence()
@@ -289,7 +290,7 @@ class Sequence(ModelSQL, ModelView):
 
     def delete_sql_sequence(self):
         'Delete the SQL sequence'
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         if self.type != 'incremental':
             return
         cursor.execute('DROP SEQUENCE "%s"'
@@ -319,7 +320,7 @@ class Sequence(ModelSQL, ModelView):
     def _get_sequence(cls, sequence):
         if sequence.type == 'incremental':
             if sql_sequence and not cls._strict:
-                cursor = Transaction().cursor
+                cursor = Transaction().connection.cursor()
                 cursor.execute('SELECT nextval(\'"%s"\')'
                     % sequence._sql_sequence_name)
                 number_next, = cursor.fetchone()
@@ -382,5 +383,6 @@ class SequenceStrict(Sequence):
 
     @classmethod
     def get_id(cls, clause):
-        Transaction().cursor.lock(cls._table)
+        transaction = Transaction()
+        transaction.database.lock(transaction.connection, cls._table)
         return super(SequenceStrict, cls).get_id(clause)
diff --git a/trytond/ir/sequence.xml b/trytond/ir/sequence.xml
index c9c3506..32ecb63 100644
--- a/trytond/ir/sequence.xml
+++ b/trytond/ir/sequence.xml
@@ -39,12 +39,12 @@ this repository contains the full copyright notices and license terms. -->
 
         <record model="ir.ui.view" id="sequence_strict_view_form">
             <field name="model">ir.sequence.strict</field>
-            <field name="type">form</field>
+            <field name="type" eval="None"/>
             <field name="inherit" ref="sequence_view_form"/>
         </record>
         <record model="ir.ui.view" id="sequence_strict_view_tree">
             <field name="model">ir.sequence.strict</field>
-            <field name="type">tree</field>
+            <field name="type" eval="None"/>
             <field name="inherit" ref="sequence_view_tree"/>
         </record>
         <record model="ir.action.act_window" id="act_sequence_strict_form">
diff --git a/trytond/ir/session.py b/trytond/ir/session.py
index 99e8e8a..c1c8c78 100644
--- a/trytond/ir/session.py
+++ b/trytond/ir/session.py
@@ -10,7 +10,6 @@ import datetime
 from trytond.model import ModelSQL, fields
 from trytond.config import config
 from .. import backend
-from ..transaction import Transaction
 
 __all__ = [
     'Session', 'SessionWizard',
@@ -34,7 +33,7 @@ class Session(ModelSQL):
         TableHandler = backend.get('TableHandler')
         super(Session, cls).__register__(module_name)
 
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.index_action('create_uid', 'add')
 
     @staticmethod
diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py
index 4e3f69f..e57e20f 100644
--- a/trytond/ir/translation.py
+++ b/trytond/ir/translation.py
@@ -1,9 +1,5 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
 import zipfile
 import polib
 import xml.dom.minidom
@@ -12,6 +8,7 @@ import os
 from hashlib import md5
 from lxml import etree
 from itertools import izip
+from io import BytesIO
 
 from sql import Column, Null
 from sql.functions import Substring, Position
@@ -19,10 +16,13 @@ from sql.conditionals import Case
 from sql.operators import Or, And
 from sql.aggregate import Max
 
+from genshi.filters.i18n import extract as genshi_extract
+from relatorio.reporting import MIMETemplateLoader
+
 from ..model import ModelView, ModelSQL, fields, Unique
 from ..wizard import Wizard, StateView, StateTransition, StateAction, \
     Button
-from ..tools import file_open, reduce_ids, grouped_slice
+from ..tools import file_open, reduce_ids, grouped_slice, cursor_dict
 from .. import backend
 from ..pyson import PYSONEncoder, Eval
 from ..transaction import Transaction
@@ -40,7 +40,7 @@ __all__ = ['Translation',
 TRANSLATION_TYPE = [
     ('field', 'Field'),
     ('model', 'Model'),
-    ('odt', 'ODT'),
+    ('report', 'Report'),
     ('selection', 'Selection'),
     ('view', 'View'),
     ('wizard_button', 'Wizard Button'),
@@ -96,9 +96,10 @@ class Translation(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         ir_translation = cls.__table__()
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         # Migration from 1.8: new field src_md5
         src_md5_exist = table.column_exist('src_md5')
         if not src_md5_exist:
@@ -114,7 +115,7 @@ class Translation(ModelSQL, ModelView):
         # Migration from 1.8: fill new field src_md5
         if not src_md5_exist:
             offset = 0
-            limit = cursor.IN_MAX
+            limit = transaction.database.IN_MAX
             translations = True
             while translations:
                 translations = cls.search([], offset=offset, limit=limit)
@@ -124,7 +125,7 @@ class Translation(ModelSQL, ModelView):
                     cls.write([translation], {
                         'src_md5': src_md5,
                     })
-            table = TableHandler(cursor, cls, module_name)
+            table = TableHandler(cls, module_name)
             table.not_null_action('src_md5', action='add')
 
         # Migration from 2.2 and 2.8
@@ -132,12 +133,18 @@ class Translation(ModelSQL, ModelView):
                 [-1], where=(ir_translation.res_id == Null)
                 | (ir_translation.res_id == 0)))
 
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        # Migration from 3.8: rename odt type in report
+        cursor.execute(*ir_translation.update(
+                [ir_translation.type],
+                ['report'],
+                where=ir_translation.type == 'odt'))
+
+        table = TableHandler(cls, module_name)
         table.index_action(['lang', 'type', 'name'], 'add')
 
     @classmethod
     def register_model(cls, model, module_name):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         ir_translation = cls.__table__()
 
         if not model.__doc__:
@@ -176,7 +183,7 @@ class Translation(ModelSQL, ModelView):
 
     @classmethod
     def register_fields(cls, model, module_name):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         ir_translation = cls.__table__()
 
         # Prefetch field translations
@@ -192,7 +199,7 @@ class Translation(ModelSQL, ModelView):
                         & ir_translation.type.in_(
                             ('field', 'help', 'selection'))
                         & ir_translation.name.in_(names))))
-            for trans in cursor.dictfetchall():
+            for trans in cursor_dict(cursor):
                 if trans['type'] == 'field':
                     trans_fields[trans['name']] = trans
                 elif trans['type'] == 'help':
@@ -263,7 +270,7 @@ class Translation(ModelSQL, ModelView):
 
     @classmethod
     def register_error_messages(cls, model, module_name):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         ir_translation = cls.__table__()
 
         cursor.execute(*ir_translation.select(
@@ -271,7 +278,7 @@ class Translation(ModelSQL, ModelView):
                 where=((ir_translation.lang == 'en_US')
                     & (ir_translation.type == 'error')
                     & (ir_translation.name == model.__name__))))
-        trans_error = dict((t['src'], t) for t in cursor.dictfetchall())
+        trans_error = {t['src']: t for t in cursor_dict(cursor)}
 
         errors = model._get_error_messages()
         for error in set(errors):
@@ -288,7 +295,7 @@ class Translation(ModelSQL, ModelView):
 
     @classmethod
     def register_wizard(cls, wizard, module_name):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         ir_translation = cls.__table__()
 
         # Prefetch button translations
@@ -297,7 +304,7 @@ class Translation(ModelSQL, ModelView):
                 where=((ir_translation.lang == 'en_US')
                     & (ir_translation.type == 'wizard_button')
                     & (ir_translation.name.like(wizard.__name__ + ',%')))))
-        trans_buttons = dict((t['name'], t) for t in cursor.dictfetchall())
+        trans_buttons = {t['name']: t for t in cursor_dict(cursor)}
 
         def update_insert_button(state_name, button):
             trans_name = '%s,%s,%s' % (
@@ -433,12 +440,13 @@ class Translation(ModelSQL, ModelView):
         else:
             to_fetch = ids
         if to_fetch:
-            cursor = Transaction().cursor
+            transaction = Transaction()
+            cursor = transaction.connection.cursor()
             table = cls.__table__()
             fuzzy_sql = table.fuzzy == False
             if Transaction().context.get('fuzzy_translation', False):
                 fuzzy_sql = None
-            in_max = cursor.IN_MAX / 7
+            in_max = transaction.database.IN_MAX // 7
             for sub_to_fetch in grouped_slice(to_fetch, in_max):
                 red_sql = reduce_ids(table.res_id, sub_to_fetch)
                 where = And(((table.lang == lang),
@@ -472,8 +480,8 @@ class Translation(ModelSQL, ModelView):
         ModelFields = pool.get('ir.model.field')
         Model = pool.get('ir.model')
         Config = pool.get('ir.configuration')
-        cursor = Transaction().cursor
-        in_max = cursor.IN_MAX
+        transaction = Transaction()
+        in_max = transaction.database.IN_MAX
 
         if len(ids) > in_max:
             for i in range(0, len(ids), in_max):
@@ -614,7 +622,7 @@ class Translation(ModelSQL, ModelView):
         if trans != -1:
             return trans
 
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         where = ((table.lang == lang)
             & (table.type == ttype)
@@ -643,9 +651,10 @@ class Translation(ModelSQL, ModelView):
         '''
         res = {}
         clause = []
-        cursor = Transaction().cursor
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
         table = cls.__table__()
-        if len(args) > cursor.IN_MAX:
+        if len(args) > transaction.database.IN_MAX:
             for sub_args in grouped_slice(args):
                 res.update(cls.get_sources(list(sub_args)))
             return res
@@ -673,7 +682,7 @@ class Translation(ModelSQL, ModelView):
                     where &= table.src == source
                 clause.append(where)
         if clause:
-            in_max = cursor.IN_MAX / 7
+            in_max = transaction.database.IN_MAX // 7
             for sub_clause in grouped_slice(clause, in_max):
                 cursor.execute(*table.select(
                         table.lang, table.type, table.name, table.src,
@@ -699,14 +708,15 @@ class Translation(ModelSQL, ModelView):
         ModelView._fields_view_get_cache.clear()
         vlist = [x.copy() for x in vlist]
 
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         for vals in vlist:
             if not vals.get('module'):
                 if Transaction().context.get('module'):
                     vals['module'] = Transaction().context['module']
-                elif vals.get('type', '') in ('odt', 'view', 'wizard_button',
-                        'selection', 'error'):
+                elif vals.get('type', '') in {
+                        'report', 'view', 'wizard_button', 'selection',
+                        'error'}:
                     cursor.execute(*table.select(table.module,
                             where=(table.name == vals.get('name') or '')
                             & (table.res_id == vals.get('res_id') or -1)
@@ -754,7 +764,8 @@ class Translation(ModelSQL, ModelView):
 
     @property
     def unique_key(self):
-        if self.type in ('odt', 'view', 'wizard_button', 'selection', 'error'):
+        if self.type in {
+                'report', 'view', 'wizard_button', 'selection', 'error'}:
             return (self.name, self.res_id, self.type, self.src)
         elif self.type in ('field', 'model', 'help'):
             return (self.name, self.res_id, self.type)
@@ -825,8 +836,9 @@ class Translation(ModelSQL, ModelView):
                     ('type', '=', new_translation.type),
                     ('module', '=', res_id_module),
                     ]
-                if new_translation.type in ('odt', 'view', 'wizard_button',
-                        'selection', 'error'):
+                if new_translation.type in {
+                        'report', 'view', 'wizard_button', 'selection',
+                        'error'}:
                     domain.append(('src', '=', new_translation.src))
                 translation, = cls.search(domain)
                 if translation.value != new_translation.value:
@@ -886,12 +898,15 @@ class Translation(ModelSQL, ModelView):
 
                 if not ids:
                     to_save.append(translation)
-                elif not noupdate:
+                else:
                     for translation_id in ids:
                         old_translation = id2translation[translation_id]
-                        old_translation.value = translation.value
-                        old_translation.fuzzy = translation.fuzzy
-                        to_save.append(old_translation)
+                        if not noupdate:
+                            old_translation.value = translation.value
+                            old_translation.fuzzy = translation.fuzzy
+                            to_save.append(old_translation)
+                        else:
+                            translations.add(old_translation)
         cls.save(to_save)
         translations |= set(to_save)
 
@@ -988,23 +1003,70 @@ class TranslationSet(Wizard):
             Button('OK', 'end', 'tryton-ok', default=True),
             ])
 
-    def _translate_report(self, node):
-        strings = []
-
-        if node.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
-            if node.parentNode \
-                    and node.parentNode.tagName in ('text:placeholder',
-                            'text:page-number', 'text:page-count'):
-                return strings
-
-            if node.nodeValue:
-                txt = node.nodeValue.strip()
-                if txt:
-                    strings.append(txt)
+    def extract_report_opendocument(self, content):
+        def extract(node):
+            if node.nodeType in {node.CDATA_SECTION_NODE, node.TEXT_NODE}:
+                if (node.parentNode
+                        and node.parentNode.tagName in {
+                            'text:placeholder',
+                            'text:page-number',
+                            'text:page-count',
+                            }):
+                    return
+                if node.nodeValue:
+                    txt = node.nodeValue.strip()
+                    if txt:
+                        yield txt
+
+            for child in [x for x in node.childNodes]:
+                for string in extract(child):
+                    yield string
+
+        content = BytesIO(content)
+        try:
+            content = zipfile.ZipFile(content, mode='r')
+        except zipfile.BadZipfile:
+            return
 
-        for child in [x for x in node.childNodes]:
-            strings.extend(self._translate_report(child))
-        return strings
+        content_xml = content.read('content.xml')
+        document = xml.dom.minidom.parseString(content_xml)
+        for string in extract(document.documentElement):
+            yield string
+
+        style_xml = content.read('styles.xml')
+        document = xml.dom.minidom.parseString(style_xml)
+        for string in extract(document.documentElement):
+            yield string
+    extract_report_odt = extract_report_opendocument
+    extract_report_odp = extract_report_opendocument
+    extract_report_ods = extract_report_opendocument
+    extract_report_odg = extract_report_opendocument
+
+    def extract_report_genshi(template_class):
+        def method(self, content,
+                keywords=None, comment_tags=None, **options):
+            options['template_class'] = template_class
+            content = BytesIO(content)
+            if keywords is None:
+                keywords = []
+            if comment_tags is None:
+                comment_tags = []
+
+            for _, _, string, _ in genshi_extract(
+                    content, keywords, comment_tags, options):
+                yield string
+        if not template_class:
+            raise ValueError('a template class is required')
+        return method
+    factories = MIMETemplateLoader().factories
+    extract_report_plain = extract_report_genshi(factories['text'])
+    extract_report_xml = extract_report_genshi(
+        factories.get('markup', factories.get('xml')))
+    extract_report_html = extract_report_genshi(
+        factories.get('markup', factories.get('xml')))
+    extract_report_xhtml = extract_report_genshi(
+        factories.get('markup', factories.get('xml')))
+    del factories
 
     def set_report(self):
         pool = Pool()
@@ -1017,43 +1079,28 @@ class TranslationSet(Wizard):
         if not reports:
             return
 
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         translation = Translation.__table__()
         for report in reports:
             cursor.execute(*translation.select(
                     translation.id, translation.name, translation.src,
                     where=(translation.lang == 'en_US')
-                    & (translation.type == 'odt')
+                    & (translation.type == 'report')
                     & (translation.name == report.report_name)
                     & (translation.module == report.module or '')))
-            trans_reports = {}
-            for trans in cursor.dictfetchall():
-                trans_reports[trans['src']] = trans
-
-            strings = []
+            trans_reports = {t['src']: t for t in cursor_dict(cursor)}
 
-            odt_content = ''
+            content = None
             if report.report:
                 with file_open(report.report.replace('/', os.sep),
                         mode='rb') as fp:
-                    odt_content = fp.read()
-            for content in (report.report_content_custom, odt_content):
+                    content = fp.read()
+            strings = []
+            for content in [report.report_content_custom, content]:
                 if not content:
                     continue
-
-                content_io = StringIO.StringIO(content)
-                try:
-                    content_z = zipfile.ZipFile(content_io, mode='r')
-                except zipfile.BadZipfile:
-                    continue
-
-                content_xml = content_z.read('content.xml')
-                document = xml.dom.minidom.parseString(content_xml)
-                strings = self._translate_report(document.documentElement)
-
-                style_xml = content_z.read('styles.xml')
-                document = xml.dom.minidom.parseString(style_xml)
-                strings += self._translate_report(document.documentElement)
+                func_name = 'extract_report_%s' % report.template_extension
+                strings.extend(getattr(self, func_name)(content))
 
             for string in {}.fromkeys(strings).keys():
                 src_md5 = Translation.get_src_md5(string)
@@ -1076,7 +1123,7 @@ class TranslationSet(Wizard):
                                     translation.src_md5],
                                 [string, True, src_md5],
                                 where=(translation.name == report.report_name)
-                                & (translation.type == 'odt')
+                                & (translation.type == 'report')
                                 & (translation.src == string_trans)
                                 & (translation.module == report.module)))
                         del trans_reports[string_trans]
@@ -1089,12 +1136,12 @@ class TranslationSet(Wizard):
                                 translation.value, translation.module,
                                 translation.fuzzy, translation.src_md5,
                                 translation.res_id],
-                            [[report.report_name, 'en_US', 'odt', string, '',
-                                    report.module, False, src_md5, -1]]))
+                            [[report.report_name, 'en_US', 'report', string,
+                                    '', report.module, False, src_md5, -1]]))
             if strings:
                 cursor.execute(*translation.delete(
                         where=(translation.name == report.report_name)
-                        & (translation.type == 'odt')
+                        & (translation.type == 'report')
                         & (translation.module == report.module)
                         & ~translation.src.in_(strings)))
 
@@ -1119,7 +1166,7 @@ class TranslationSet(Wizard):
 
         if not views:
             return
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         translation = Translation.__table__()
         for view in views:
             cursor.execute(*translation.select(
@@ -1128,9 +1175,7 @@ class TranslationSet(Wizard):
                     & (translation.type == 'view')
                     & (translation.name == view.model)
                     & (translation.module == view.module)))
-            trans_views = {}
-            for trans in cursor.dictfetchall():
-                trans_views[trans['src']] = trans
+            trans_views = {t['src']: t for t in cursor_dict(cursor)}
 
             xml = (view.arch or '').strip()
             if not xml:
@@ -1145,7 +1190,7 @@ class TranslationSet(Wizard):
                     ('module', '=', view.module),
                     ])
             for view2 in views2:
-                xml2 = view2.arch.strip()
+                xml2 = view2.arch
                 if not xml2:
                     continue
                 tree2 = etree.fromstring(xml2)
@@ -1261,7 +1306,7 @@ class TranslationClean(Wizard):
             return True
 
     @staticmethod
-    def _clean_odt(translation):
+    def _clean_report(translation):
         pool = Pool()
         Report = pool.get('ir.action.report')
         with Transaction().set_context(active_test=False):
@@ -1432,7 +1477,7 @@ class TranslationUpdateStart(ModelView):
     @staticmethod
     def default_language():
         Lang = Pool().get('ir.lang')
-        code = Transaction().context.get('language', False)
+        code = Transaction().context.get('language')
         try:
             lang, = Lang.search([
                     ('code', '=', code),
@@ -1447,7 +1492,7 @@ class TranslationUpdate(Wizard):
     "Update translation"
     __name__ = "ir.translation.update"
 
-    _source_types = ['odt', 'view', 'wizard_button', 'selection', 'error']
+    _source_types = ['report', 'view', 'wizard_button', 'selection', 'error']
     _ressource_types = ['field', 'model', 'help']
     _updatable_types = ['field', 'model', 'selection', 'help']
 
@@ -1465,7 +1510,8 @@ class TranslationUpdate(Wizard):
     def do_update(self, action):
         pool = Pool()
         Translation = pool.get('ir.translation')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
+        cursor_update = Transaction().connection.cursor()
         translation = Translation.__table__()
         lang = self.start.language.code
         columns = [translation.name.as_('name'),
@@ -1478,7 +1524,7 @@ class TranslationUpdate(Wizard):
                     where=(translation.lang == lang)
                     & translation.type.in_(self._source_types))))
         to_create = []
-        for row in cursor.dictfetchall():
+        for row in cursor_dict(cursor):
             to_create.append({
                 'name': row['name'],
                 'res_id': row['res_id'],
@@ -1499,7 +1545,7 @@ class TranslationUpdate(Wizard):
                     where=(translation.lang == lang)
                     & translation.type.in_(self._ressource_types))))
         to_create = []
-        for row in cursor.dictfetchall():
+        for row in cursor_dict(cursor):
             to_create.append({
                 'name': row['name'],
                 'res_id': row['res_id'],
@@ -1518,8 +1564,8 @@ class TranslationUpdate(Wizard):
                 - translation.select(*columns,
                     where=(translation.lang == lang)
                     & translation.type.in_(self._updatable_types))))
-        for row in cursor.dictfetchall():
-            cursor.execute(*translation.update(
+        for row in cursor_dict(cursor):
+            cursor_update.execute(*translation.update(
                     [translation.fuzzy, translation.src],
                     [True, row['src']],
                     where=(translation.name == row['name'])
@@ -1541,15 +1587,15 @@ class TranslationUpdate(Wizard):
                 & (translation.value != Null),
                 group_by=translation.src))
 
-        for row in cursor.dictfetchall():
-            cursor.execute(*translation.update(
+        for row in cursor_dict(cursor):
+            cursor_update.execute(*translation.update(
                     [translation.fuzzy, translation.value],
                     [True, row['value']],
                     where=(translation.src == row['src'])
                     & ((translation.value == '') | (translation.value == Null))
                     & (translation.lang == lang)))
 
-        cursor.execute(*translation.update(
+        cursor_update.execute(*translation.update(
                 [translation.fuzzy],
                 [False],
                 where=((translation.value == '') | (translation.value == Null))
@@ -1579,7 +1625,7 @@ class TranslationExportStart(ModelView):
     @classmethod
     def default_language(cls):
         Lang = Pool().get('ir.lang')
-        code = Transaction().context.get('language', False)
+        code = Transaction().context.get('language')
         domain = [('code', '=', code)] + cls.language.domain
         try:
             lang, = Lang.search(domain, limit=1)
diff --git a/trytond/ir/trigger.py b/trytond/ir/trigger.py
index 18b8e8e..29b4683 100644
--- a/trytond/ir/trigger.py
+++ b/trytond/ir/trigger.py
@@ -74,8 +74,8 @@ class Trigger(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
-        table = TableHandler(cursor, cls, module_name)
+        cursor = Transaction().connection.cursor()
+        table = TableHandler(cls, module_name)
         sql_table = cls.__table__()
 
         super(Trigger, cls).__register__(module_name)
@@ -187,7 +187,7 @@ class Trigger(ModelSQL, ModelView):
         TriggerLog = pool.get('ir.trigger.log')
         Model = pool.get(trigger.model.model)
         ActionModel = pool.get(trigger.action_model.model)
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         trigger_log = TriggerLog.__table__()
         ids = map(int, records)
 
@@ -218,7 +218,7 @@ class Trigger(ModelSQL, ModelView):
                 red_sql = reduce_ids(trigger_log.record_id, sub_ids)
                 cursor.execute(*trigger_log.select(
                         trigger_log.record_id, Max(trigger_log.create_date),
-                        where=red_sql & (trigger_log.trigger == trigger.id),
+                        where=(red_sql & (trigger_log.trigger == trigger.id)),
                         group_by=trigger_log.record_id))
                 delay = dict(cursor.fetchall())
                 for record_id in sub_ids:
@@ -236,8 +236,8 @@ class Trigger(ModelSQL, ModelView):
                             microseconds = int(timepart_full[1])
                         else:
                             microseconds = 0
-                        delay[record_id] = datetime.datetime(year, month, day,
-                                hours, minutes, seconds, microseconds)
+                        delay[record_id] = datetime.datetime(year, month,
+                            day, hours, minutes, seconds, microseconds)
                     if (datetime.datetime.now() - delay[record_id]
                             >= trigger.minimum_time_delay):
                         new_ids.append(record_id)
@@ -307,5 +307,5 @@ class TriggerLog(ModelSQL):
         TableHandler = backend.get('TableHandler')
         super(TriggerLog, cls).__register__(module_name)
 
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.index_action(['trigger', 'record_id'], 'add')
diff --git a/trytond/ir/tryton.cfg b/trytond/ir/tryton.cfg
index d905607..152b3e1 100644
--- a/trytond/ir/tryton.cfg
+++ b/trytond/ir/tryton.cfg
@@ -9,6 +9,7 @@ xml:
     model.xml
     sequence.xml
     attachment.xml
+    note.xml
     cron.xml
     lang.xml
     translation.xml
diff --git a/trytond/ir/ui/form.rnc b/trytond/ir/ui/form.rnc
index 6c1350a..432ab2f 100644
--- a/trytond/ir/ui/form.rnc
+++ b/trytond/ir/ui/form.rnc
@@ -88,9 +88,6 @@ attlist.field &= attribute view_ids { text }?
 attlist.field &= attribute product { text }?
 attlist.field &=
   [ a:defaultValue = "0" ] attribute invisible { "0" | "1" }?
-attlist.field &= attribute sum { text }?
-attlist.field &= attribute key { text }?
-attlist.field &= attribute color { text }?
 attlist.field &=
   [ a:defaultValue = "left_to_right" ] attribute orientation {
     "left_to_right"
diff --git a/trytond/ir/ui/form.rng b/trytond/ir/ui/form.rng
index 8d105cc..74b01fc 100644
--- a/trytond/ir/ui/form.rng
+++ b/trytond/ir/ui/form.rng
@@ -302,21 +302,6 @@
   </define>
   <define name="attlist.field" combine="interleave">
     <optional>
-      <attribute name="sum"/>
-    </optional>
-  </define>
-  <define name="attlist.field" combine="interleave">
-    <optional>
-      <attribute name="key"/>
-    </optional>
-  </define>
-  <define name="attlist.field" combine="interleave">
-    <optional>
-      <attribute name="color"/>
-    </optional>
-  </define>
-  <define name="attlist.field" combine="interleave">
-    <optional>
       <attribute name="orientation" a:defaultValue="left_to_right">
         <choice>
           <value>left_to_right</value>
diff --git a/trytond/ir/ui/icon.py b/trytond/ir/ui/icon.py
index b42a16f..2f419a3 100644
--- a/trytond/ir/ui/icon.py
+++ b/trytond/ir/ui/icon.py
@@ -50,5 +50,5 @@ class Icon(ModelSQL, ModelView):
 
     def get_icon(self, name):
         path = os.path.join(self.module, self.path.replace('/', os.sep))
-        with file_open(path, subdir='modules') as fp:
+        with file_open(path, subdir='modules', mode='rb') as fp:
             return fp.read()
diff --git a/trytond/ir/ui/menu.py b/trytond/ir/ui/menu.py
index e7ee292..00ac991 100644
--- a/trytond/ir/ui/menu.py
+++ b/trytond/ir/ui/menu.py
@@ -225,9 +225,9 @@ class UIMenu(ModelSQL, ModelView):
         pool = Pool()
         ActionKeyword = pool.get('ir.action.keyword')
         action_keywords = []
-        cursor = Transaction().cursor
-        for i in range(0, len(menus), cursor.IN_MAX):
-            sub_menus = menus[i:i + cursor.IN_MAX]
+        transaction = Transaction()
+        for i in range(0, len(menus), transaction.database.IN_MAX):
+            sub_menus = menus[i:i + transaction.database.IN_MAX]
             action_keywords += ActionKeyword.search([
                 ('keyword', '=', 'tree_open'),
                 ('model', 'in', [str(menu) for menu in sub_menus]),
diff --git a/trytond/ir/ui/tree.rnc b/trytond/ir/ui/tree.rnc
index 2b61f69..c044817 100644
--- a/trytond/ir/ui/tree.rnc
+++ b/trytond/ir/ui/tree.rnc
@@ -62,6 +62,7 @@ attlist.field &= [a:defaultValue = "1"] attribute completion { "0" | "1" }?
 attlist.field &= attribute string { text }?
 attlist.field &= [a:defaultValue = "1"] attribute factor { text }?
 attlist.field &= attribute filename { text }?
+attlist.field &= attribute view_ids { text }?
 prefix = element prefix { attlist.affix, empty }
 suffix = element suffix { attlist.affix, empty }
 attlist.affix &= attribute string { text }?
diff --git a/trytond/ir/ui/tree.rng b/trytond/ir/ui/tree.rng
index 4e4a987..3b5d21d 100644
--- a/trytond/ir/ui/tree.rng
+++ b/trytond/ir/ui/tree.rng
@@ -198,6 +198,11 @@
       <attribute name="filename"/>
     </optional>
   </define>
+  <define name="attlist.field" combine="interleave">
+    <optional>
+      <attribute name="view_ids"/>
+    </optional>
+  </define>
   <define name="prefix">
     <element name="prefix">
       <ref name="attlist.affix"/>
diff --git a/trytond/ir/ui/view.py b/trytond/ir/ui/view.py
index 0492ad4..3b6c9bc 100644
--- a/trytond/ir/ui/view.py
+++ b/trytond/ir/ui/view.py
@@ -11,7 +11,7 @@ except ImportError:
 from lxml import etree
 from trytond.model import ModelView, ModelSQL, fields
 from trytond import backend
-from trytond.pyson import Eval, Bool, PYSONDecoder
+from trytond.pyson import Eval, Bool, PYSONDecoder, If
 from trytond.tools import file_open
 from trytond.transaction import Transaction
 from trytond.wizard import Wizard, StateView, Button
@@ -42,7 +42,13 @@ class View(ModelSQL, ModelView):
             ('graph', 'Graph'),
             ('calendar', 'Calendar'),
             ('board', 'Board'),
-            ], 'View Type', select=True)
+            ], 'View Type', select=True,
+        domain=[
+            If(Bool(Eval('inherit')),
+                ('type', '=', None),
+                ('type', '!=', None)),
+            ],
+        depends=['inherit'])
     data = fields.Text('Data')
     name = fields.Char('Name', states={
             'invisible': ~(Eval('module') & Eval('name')),
@@ -79,8 +85,7 @@ class View(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.4 arch moved into data
         if table.column_exist('arch'):
@@ -89,7 +94,7 @@ class View(ModelSQL, ModelView):
         super(View, cls).__register__(module_name)
 
         # New instance to refresh definition
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 1.0 arch no more required
         table.not_null_action('arch', action='remove')
@@ -115,13 +120,22 @@ class View(ModelSQL, ModelView):
         key = (cls.__name__, type_)
         rng = cls._get_rng_cache.get(key)
         if rng is None:
-            rng_name = os.path.join(os.path.dirname(
-                    unicode(__file__, sys.getfilesystemencoding())),
-                type_ + '.rng')
-            rng = etree.fromstring(open(rng_name).read())
+            if sys.version_info < (3,):
+                filename = __file__.decode(sys.getfilesystemencoding())
+            else:
+                filename = __file__
+            rng_name = os.path.join(os.path.dirname(filename), type_ + '.rng')
+            with open(rng_name, 'rb') as fp:
+                rng = etree.fromstring(fp.read())
             cls._get_rng_cache.set(key, rng)
         return rng
 
+    @property
+    def rng_type(self):
+        if self.inherit:
+            return self.inherit.rng_type
+        return self.type
+
     @classmethod
     def validate(cls, views):
         super(View, cls).validate(views)
@@ -139,14 +153,14 @@ class View(ModelSQL, ModelView):
             tree = etree.fromstring(xml)
 
             if hasattr(etree, 'RelaxNG'):
-                rng_type = view.inherit.type if view.inherit else view.type
-                validator = etree.RelaxNG(etree=cls.get_rng(rng_type))
+                validator = etree.RelaxNG(etree=cls.get_rng(view.rng_type))
                 if not validator.validate(tree):
-                    error_log = reduce(lambda x, y: str(x) + '\n' + str(y),
-                            validator.error_log.filter_from_errors())
-                    logger.error('Invalid xml view:\n%s',
-                        str(error_log) + '\n' + xml)
-                    cls.raise_user_error('invalid_xml', (view.rec_name,))
+                    error_log = '\n'.join(map(str,
+                            validator.error_log.filter_from_errors()))
+                    logger.error('Invalid XML view %s:\n%s\n%s',
+                        view.rec_name, error_log, xml)
+                    cls.raise_user_error(
+                        'invalid_xml', (view.rec_name,), error_log)
             root_element = tree.getroottree().getroot()
 
             # validate pyson attributes
@@ -156,29 +170,30 @@ class View(ModelSQL, ModelView):
 
             def encode(element):
                 for attr in ('states', 'domain', 'spell'):
-                    if element.get(attr):
-                        try:
-                            value = PYSONDecoder().decode(element.get(attr))
-                            validates.get(attr, lambda a: True)(value)
-                        except Exception, e:
-                            logger.error('Invalid pyson view element "%s:%s":'
-                                '\n%s\n%s',
-                                element.get('id') or element.get('name'), attr,
-                                str(e), xml)
-                            return False
+                    if not element.get(attr):
+                        continue
+                    try:
+                        value = PYSONDecoder().decode(element.get(attr))
+                        validates.get(attr, lambda a: True)(value)
+                    except Exception, e:
+                        error_log = '%s: <%s %s="%s"/>' % (
+                            e, element.get('id') or element.get('name'), attr,
+                            element.get(attr))
+                        logger.error(
+                            'Invalid XML view %s:\n%s\n%s',
+                            view.rec_name, error_log, xml)
+                        cls.raise_user_error(
+                            'invalid_xml', (view.rec_name,), error_log)
                 for child in element:
-                    if not encode(child):
-                        return False
-                return True
-            if not encode(root_element):
-                cls.raise_user_error('invalid_xml', (view.rec_name,))
+                    encode(child)
+            encode(root_element)
 
     def get_arch(self, name):
         value = None
         if self.name and self.module:
             path = os.path.join(self.module, 'view', self.name + '.xml')
             try:
-                with file_open(path, subdir='modules') as fp:
+                with file_open(path, subdir='modules', mode='rb') as fp:
                     value = fp.read()
             except IOError:
                 pass
@@ -320,16 +335,14 @@ class ViewTreeState(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.8: table name changed
-        table.table_rename(cursor, 'ir_ui_view_tree_expanded_state',
-            cls._table)
+        table.table_rename('ir_ui_view_tree_expanded_state', cls._table)
 
         super(ViewTreeState, cls).__register__(module_name)
 
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.index_action(['model', 'domain', 'user', 'child_name'], 'add')
 
     @staticmethod
diff --git a/trytond/ir/view/action_act_window_form.xml b/trytond/ir/view/action_act_window_form.xml
index 2cef84f..36d112d 100644
--- a/trytond/ir/view/action_act_window_form.xml
+++ b/trytond/ir/view/action_act_window_form.xml
@@ -7,25 +7,27 @@ this repository contains the full copyright notices and license terms. -->
     <label name="active"/>
     <field name="active" xexpand="0" width="100"/>
     <notebook colspan="4">
-        <page string="General" id="general" col="6">
+        <page string="General" id="general">
             <label name="res_model"/>
             <field name="res_model"/>
+            <label name="context_model"/>
+            <field name="context_model"/>
             <label name="usage"/>
             <field name="usage"/>
             <label name="icon"/>
             <field name="icon"/>
-            <field name="act_window_views" colspan="6"
+            <field name="act_window_views" colspan="4"
                 view_ids="ir.act_window_view_view_list2"/>
-            <field name="act_window_domains" colspan="6"
+            <field name="act_window_domains" colspan="4"
                 view_ids="ir.act_window_domain_view_list2"/>
             <label name="domain"/>
-            <field name="domain" colspan="5"/>
+            <field name="domain" colspan="3"/>
             <label name="context"/>
-            <field name="context" colspan="5"/>
+            <field name="context" colspan="3"/>
             <label name="order"/>
-            <field name="order" colspan="5"/>
+            <field name="order" colspan="3"/>
             <label name="search_value"/>
-            <field name="search_value" colspan="5"/>
+            <field name="search_value" colspan="3"/>
             <label name="limit"/>
             <field name="limit"/>
             <label name="window_name"/>
diff --git a/trytond/ir/view/cron_form.xml b/trytond/ir/view/cron_form.xml
index 7367844..7f3355d 100644
--- a/trytond/ir/view/cron_form.xml
+++ b/trytond/ir/view/cron_form.xml
@@ -20,6 +20,7 @@ this repository contains the full copyright notices and license terms. -->
     <field name="next_call"/>
     <label name="repeat_missed"/>
     <field name="repeat_missed"/>
+    <button name="run_once" colspan="2" string="Run Once"/>
     <separator string="Action to trigger" colspan="4"
         id="action_trigger"/>
     <label name="model"/>
diff --git a/trytond/ir/view/cron_list.xml b/trytond/ir/view/cron_list.xml
index b8a2e86..190fa4f 100644
--- a/trytond/ir/view/cron_list.xml
+++ b/trytond/ir/view/cron_list.xml
@@ -11,4 +11,5 @@ this repository contains the full copyright notices and license terms. -->
     <field name="interval_type"/>
     <field name="number_calls"/>
     <field name="active"/>
+    <button name="run_once" string="Run Once" tree_invisible="1"/>
 </tree>
diff --git a/trytond/ir/view/note_form.xml b/trytond/ir/view/note_form.xml
new file mode 100644
index 0000000..cea7919
--- /dev/null
+++ b/trytond/ir/view/note_form.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<form string="Note" col="6">
+    <label name="resource"/>
+    <field name="resource" colspan="5"/>
+    <label name="last_user"/>
+    <field name="last_user"/>
+    <label name="last_modification"/>
+    <field name="last_modification"/>
+    <label name="unread"/>
+    <field name="unread"/>
+    <field name="message" colspan="6"/>
+</form>
diff --git a/trytond/ir/view/note_list.xml b/trytond/ir/view/note_list.xml
new file mode 100644
index 0000000..cbb08b0
--- /dev/null
+++ b/trytond/ir/view/note_list.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree string="Notes">
+    <field name="unread"/>
+    <field name="resource"/>
+    <field name="last_user" string="User"/>
+    <field name="last_modification" widget="date" string="Date"/>
+    <field name="last_modification" widget="time" string="Time"/>
+    <field name="message_wrapped" expand="1"/>
+</tree>
diff --git a/trytond/model/fields/binary.py b/trytond/model/fields/binary.py
index ab65b91..43795d4 100644
--- a/trytond/model/fields/binary.py
+++ b/trytond/model/fields/binary.py
@@ -45,8 +45,8 @@ class Binary(Field):
         res = {}
         converter = cls.cast
         default = None
-        format_ = Transaction().context.pop('%s.%s' % (model.__name__, name),
-            '')
+        format_ = Transaction().context.get(
+            '%s.%s' % (model.__name__, name), '')
         if format_ == 'size':
             converter = len
             default = 0
diff --git a/trytond/model/fields/char.py b/trytond/model/fields/char.py
index d2d6b61..83ba323 100644
--- a/trytond/model/fields/char.py
+++ b/trytond/model/fields/char.py
@@ -1,5 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+import sys
 import warnings
 
 from sql import Query, Expression
@@ -53,7 +54,7 @@ class Char(FieldTranslate):
             return value
         if value is None:
             return None
-        elif isinstance(value, str):
+        elif isinstance(value, str) and sys.version_info < (3,):
             return unicode(value, 'utf-8')
         assert isinstance(value, unicode)
         return value
diff --git a/trytond/model/fields/field.py b/trytond/model/fields/field.py
index d09bdb0..aff2085 100644
--- a/trytond/model/fields/field.py
+++ b/trytond/model/fields/field.py
@@ -229,6 +229,8 @@ class Field(object):
         if inst is None:
             return self
         assert self.name is not None
+        if self.name == 'id':
+            return inst._id
         return inst.__getattr__(self.name)
 
     def __set__(self, inst, value):
diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py
index b0b81f8..58514e4 100644
--- a/trytond/model/fields/many2many.py
+++ b/trytond/model/fields/many2many.py
@@ -241,23 +241,39 @@ class Many2Many(Field):
         value = tuple(instance(x) for x in (value or []))
         super(Many2Many, self).__set__(inst, value)
 
-    def convert_domain_child(self, domain, tables):
+    def convert_domain_tree(self, domain, tables):
         Target = self.get_target()
         table, _ = tables[None]
         name, operator, ids = domain
-        ids = list(ids)  # Ensure it is a list for concatenation
+        ids = set(ids)  # Ensure it is a set for concatenation
 
         def get_child(ids):
             if not ids:
-                return []
+                return set()
             children = Target.search([
                     (name, 'in', ids),
                     (name, '!=', None),
                     ], order=[])
-            child_ids = get_child([c.id for c in children])
-            return ids + child_ids
-        expression = table.id.in_(ids + get_child(ids))
-        if operator == 'not child_of':
+            child_ids = get_child(set(c.id for c in children))
+            return ids | child_ids
+
+        def get_parent(ids):
+            if not ids:
+                return set()
+            parent_ids = set()
+            for parent in Target.browse(ids):
+                parent_ids.update(p.id for p in getattr(parent, name))
+            return ids | get_parent(parent_ids)
+
+        if operator.endswith('child_of'):
+            ids = list(get_child(ids))
+        else:
+            ids = list(get_parent(ids))
+        if not ids:
+            expression = Literal(False)
+        else:
+            expression = table.id.in_(ids)
+        if operator.startswith('not'):
             return ~expression
         return expression
 
@@ -270,6 +286,7 @@ class Many2Many(Field):
         transaction = Transaction()
         table, _ = tables[None]
         name, operator, value = domain[:3]
+        assert operator not in {'where', 'not where'} or '.' not in name
 
         if Relation._history and transaction.context.get('_datetime'):
             relation = Relation.__table_history__()
@@ -290,10 +307,15 @@ class Many2Many(Field):
 
         target = getattr(Relation, self.target).sql_column(relation)
         if '.' not in name:
-            if operator in ('child_of', 'not child_of'):
+            if operator.endswith('child_of') or operator.endswith('parent_of'):
                 if Target != Model:
-                    query = Target.search([(domain[3], 'child_of', value)],
-                        order=[], query=True)
+                    if operator.endswith('child_of'):
+                        target_operator = 'child_of'
+                    else:
+                        target_operator = 'parent_of'
+                    query = Target.search([
+                            (domain[3], target_operator, value),
+                            ], order=[], query=True)
                     where = (target.in_(query) & (origin != Null))
                     if history_where:
                         where &= history_where
@@ -301,7 +323,7 @@ class Many2Many(Field):
                         where &= origin_where
                     query = relation.select(origin, where=where)
                     expression = table.id.in_(query)
-                    if operator == 'not child_of':
+                    if operator.startswith('not'):
                         return ~expression
                     return expression
                 if isinstance(value, basestring):
@@ -313,12 +335,12 @@ class Many2Many(Field):
                 else:
                     ids = value
                 if not ids:
-                    expression = table.id.in_([None])
-                    if operator == 'not child_of':
+                    expression = Literal(False)
+                    if operator.startswith('not'):
                         return ~expression
                     return expression
                 else:
-                    return self.convert_domain_child(
+                    return self.convert_domain_tree(
                         (name, operator, ids), tables)
 
             if value is None:
@@ -340,11 +362,18 @@ class Many2Many(Field):
         else:
             _, target_name = name.split('.', 1)
 
-        relation_domain = [('%s.%s' % (self.target, target_name),)
-            + tuple(domain[1:])]
-        if origin_field._type == 'reference':
-            relation_domain.append(
-                (self.origin, 'like', Model.__name__ + ',%'))
+        if operator not in {'where', 'not where'}:
+            relation_domain = [('%s.%s' % (self.target, target_name),)
+                + tuple(domain[1:])]
+            if origin_field._type == 'reference':
+                relation_domain.append(
+                    (self.origin, 'like', Model.__name__ + ',%'))
+        else:
+            relation_domain = []
+            for clause in value:
+                relation_domain.append(
+                        ('%s.%s' % (self.target, clause[0]),)
+                        + tuple(clause[1:]))
         rule_domain = Rule.domain_get(Relation.__name__, mode='read')
         if rule_domain:
             relation_domain = [relation_domain, rule_domain]
@@ -355,4 +384,8 @@ class Many2Many(Field):
             relation_domain, tables=relation_tables)
         query_table = convert_from(None, relation_tables)
         query = query_table.select(origin, where=expression)
-        return table.id.in_(query)
+        expression = table.id.in_(query)
+
+        if operator == 'not where':
+            expression = ~expression
+        return expression
diff --git a/trytond/model/fields/many2one.py b/trytond/model/fields/many2one.py
index 740ea5d..f5bfaed 100644
--- a/trytond/model/fields/many2one.py
+++ b/trytond/model/fields/many2one.py
@@ -1,6 +1,5 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from types import NoneType
 from sql import Query, Expression, Literal
 from sql.operators import Or
 
@@ -76,7 +75,7 @@ class Many2One(Field):
             value = Target(**value)
         elif isinstance(value, (int, long)):
             value = Target(value)
-        assert isinstance(value, (Target, NoneType))
+        assert isinstance(value, (Target, type(None)))
         super(Many2One, self).__set__(inst, value)
 
     @staticmethod
@@ -97,8 +96,8 @@ class Many2One(Field):
         else:
             return SQLType('INTEGER', 'INTEGER')
 
-    def convert_domain_child_mptt(self, domain, tables):
-        cursor = Transaction().cursor
+    def convert_domain_mptt(self, domain, tables):
+        cursor = Transaction().connection.cursor()
         table, _ = tables[None]
         name, operator, ids = domain
         red_sql = reduce_ids(table.id, ids)
@@ -108,30 +107,48 @@ class Many2One(Field):
         cursor.execute(*table.select(left, right, where=red_sql))
         where = Or()
         for l, r in cursor.fetchall():
-            where.append((left >= l) & (right <= r))
+            if operator.endswith('child_of'):
+                where.append((left >= l) & (right <= r))
+            else:
+                where.append((left <= l) & (right >= r))
         if not where:
             where = Literal(False)
-        if operator == 'not child_of':
+        if operator.startswith('not'):
             return ~where
         return where
 
-    def convert_domain_child(self, domain, tables):
+    def convert_domain_tree(self, domain, tables):
         Target = self.get_target()
         table, _ = tables[None]
         name, operator, ids = domain
-        ids = list(ids)  # Ensure it is a list for concatenation
+        ids = set(ids)  # Ensure it is a set for concatenation
 
         def get_child(ids):
             if not ids:
-                return []
+                return set()
             children = Target.search([
                     (name, 'in', ids),
                     (name, '!=', None),
                     ], order=[])
-            child_ids = get_child([c.id for c in children])
-            return ids + child_ids
-        expression = table.id.in_(ids + get_child(ids))
-        if operator == 'not child_of':
+            child_ids = get_child(set(c.id for c in children))
+            return ids | child_ids
+
+        def get_parent(ids):
+            if not ids:
+                return set()
+            parent_ids = set(getattr(p, name).id
+                for p in Target.browse(ids) if getattr(p, name))
+            return ids | get_parent(parent_ids)
+
+        if operator.endswith('child_of'):
+            ids = list(get_child(ids))
+        else:
+            ids = list(get_parent(ids))
+        if not ids:
+            expression = Literal(False)
+        else:
+            expression = table.id.in_(ids)
+        if operator.startswith('not'):
             return ~expression
         return expression
 
@@ -144,12 +161,17 @@ class Many2One(Field):
         name, operator, value = domain[:3]
         column = self.sql_column(table)
         if '.' not in name:
-            if operator in ('child_of', 'not child_of'):
+            if operator.endswith('child_of') or operator.endswith('parent_of'):
                 if Target != Model:
-                    query = Target.search([(domain[3], 'child_of', value)],
-                        order=[], query=True)
+                    if operator.endswith('child_of'):
+                        target_operator = 'child_of'
+                    else:
+                        target_operator = 'parent_of'
+                    query = Target.search([
+                            (domain[3], target_operator, value),
+                            ], order=[], query=True)
                     expression = column.in_(query)
-                    if operator == 'not child_of':
+                    if operator.startswith('not'):
                         return ~expression
                     return expression
 
@@ -162,15 +184,15 @@ class Many2One(Field):
                 else:
                     ids = value
                 if not ids:
-                    expression = column.in_([None])
-                    if operator == 'not child_of':
+                    expression = Literal(False)
+                    if operator.startswith('not'):
                         return ~expression
                     return expression
                 elif self.left and self.right:
-                    return self.convert_domain_child_mptt(
+                    return self.convert_domain_mptt(
                         (name, operator, ids), tables)
                 else:
-                    return self.convert_domain_child(
+                    return self.convert_domain_tree(
                         (name, operator, ids), tables)
 
             if not isinstance(value, basestring):
diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py
index d2c1a43..a94b720 100644
--- a/trytond/model/fields/one2many.py
+++ b/trytond/model/fields/one2many.py
@@ -231,6 +231,7 @@ class One2Many(Field):
         transaction = Transaction()
         table, _ = tables[None]
         name, operator, value = domain[:3]
+        assert operator not in {'where', 'not where'} or '.' not in name
 
         if Target._history and transaction.context.get('_datetime'):
             target = Target.__table_history__()
@@ -268,7 +269,10 @@ class One2Many(Field):
                     target_name = 'id'
         else:
             _, target_name = name.split('.', 1)
-        target_domain = [(target_name,) + tuple(domain[1:])]
+        if operator not in {'where', 'not where'}:
+            target_domain = [(target_name,) + tuple(domain[1:])]
+        else:
+            target_domain = value
         if origin_field._type == 'reference':
             target_domain.append(
                 (self.field, 'like', Model.__name__ + ',%'))
@@ -282,4 +286,8 @@ class One2Many(Field):
             target_domain, tables=target_tables)
         query_table = convert_from(None, target_tables)
         query = query_table.select(origin, where=expression)
-        return table.id.in_(query)
+        expression = table.id.in_(query)
+
+        if operator == 'not where':
+            expression = ~expression
+        return expression
diff --git a/trytond/model/fields/one2one.py b/trytond/model/fields/one2one.py
index 60139dc..3b9e322 100644
--- a/trytond/model/fields/one2one.py
+++ b/trytond/model/fields/one2one.py
@@ -1,6 +1,5 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from types import NoneType
 
 from trytond.model.fields.field import Field
 from trytond.model.fields.many2many import Many2Many
@@ -59,5 +58,5 @@ class One2One(Many2Many):
             value = Target(*value)
         elif isinstance(value, (int, long)):
             value = Target(value)
-        assert isinstance(value, (Target, NoneType))
+        assert isinstance(value, (Target, type(None)))
         Field.__set__(self, inst, value)
diff --git a/trytond/model/fields/property.py b/trytond/model/fields/property.py
index 4cac907..e04da69 100644
--- a/trytond/model/fields/property.py
+++ b/trytond/model/fields/property.py
@@ -72,7 +72,7 @@ class Property(Function):
         Property = pool.get('ir.property')
         IrModel = pool.get('ir.model')
         Field = pool.get('ir.model.field')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         name, operator, value = domain
 
@@ -135,7 +135,7 @@ class Property(Function):
             return [('id', 'in', [x[0] for x in props])]
 
         else:
-            other_ids = [x[0] for x in cursor.fetchall()]
+            other_ids = [x[0] for x in fetchall]
 
             res_ids = Model.search(['OR',
                 ('id', 'in', [x[0] for x in props]),
diff --git a/trytond/model/fields/reference.py b/trytond/model/fields/reference.py
index 970351c..8489a8a 100644
--- a/trytond/model/fields/reference.py
+++ b/trytond/model/fields/reference.py
@@ -1,6 +1,5 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from types import NoneType
 import warnings
 
 from sql import Cast, Literal, Query, Expression
@@ -93,7 +92,7 @@ class Reference(Field):
 
     def __set__(self, inst, value):
         from ..model import Model
-        if not isinstance(value, (Model, NoneType)):
+        if not isinstance(value, (Model, type(None))):
             if isinstance(value, basestring):
                 target, value = value.split(',')
             else:
diff --git a/trytond/model/fields/selection.py b/trytond/model/fields/selection.py
index bd29efe..92221f4 100644
--- a/trytond/model/fields/selection.py
+++ b/trytond/model/fields/selection.py
@@ -5,6 +5,7 @@ import warnings
 from sql.conditionals import Case
 
 from ... import backend
+from ...transaction import Transaction
 from .field import Field, SQLType
 
 
@@ -82,7 +83,9 @@ class TranslatedSelection(object):
     def __get__(self, inst, cls):
         if inst is None:
             return self
-        selection = dict(cls.fields_get([self.name])[self.name]['selection'])
+        with Transaction().set_context(getattr(inst, '_context', {})):
+            selection = dict(
+                cls.fields_get([self.name])[self.name]['selection'])
         value = getattr(inst, self.name)
         # None and '' are equivalent
         if value is None or value == '':
diff --git a/trytond/model/model.py b/trytond/model/model.py
index 17861e4..68177bf 100644
--- a/trytond/model/model.py
+++ b/trytond/model/model.py
@@ -3,7 +3,6 @@
 
 import copy
 import collections
-import warnings
 from functools import total_ordering
 
 from trytond.model import fields
@@ -347,42 +346,34 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
         super(Model, self).__init__()
         if id is not None:
             id = int(id)
-        self.__dict__['id'] = id
-        self._values = None
-        parent_values = {}
-        for name, value in kwargs.iteritems():
-            if not name.startswith('_parent_'):
-                setattr(self, name, value)
-            else:
-                parent_values[name] = value
-        for name, value in parent_values.iteritems():
-            parent_name, field = name.split('.', 1)
-            parent_name = parent_name[8:]  # Strip '_parent_'
-            parent = getattr(self, parent_name, None)
-            if parent is not None:
-                setattr(parent, field, value)
-            else:
-                setattr(self, parent_name, {field: value})
-        self._init_values = self._values.copy() if self._values else None
+        self._id = id
+        if kwargs:
+            self._values = {}
+            parent_values = {}
+            for name, value in kwargs.iteritems():
+                if not name.startswith('_parent_'):
+                    setattr(self, name, value)
+                else:
+                    parent_values[name] = value
+            for name, value in parent_values.iteritems():
+                parent_name, field = name.split('.', 1)
+                parent_name = parent_name[8:]  # Strip '_parent_'
+                parent = getattr(self, parent_name, None)
+                if parent is not None:
+                    setattr(parent, field, value)
+                else:
+                    setattr(self, parent_name, {field: value})
+            self._init_values = self._values.copy()
+        else:
+            self._values = None
+            self._init_values = None
 
     def __getattr__(self, name):
-        if name == 'id':
-            return self.__dict__['id']
-        elif self._values and name in self._values:
-            return self._values.get(name)
-        raise AttributeError("'%s' Model has no attribute '%s': %s"
-            % (self.__name__, name, self._values))
-
-    def __setattr__(self, name, value):
-        if name == 'id':
-            self.__dict__['id'] = value
-            return
-        super(Model, self).__setattr__(name, value)
-
-    def __getitem__(self, name):
-        warnings.warn('Use __getattr__ instead of __getitem__',
-            DeprecationWarning, stacklevel=2)
-        return getattr(self, name)
+        try:
+            return self._values[name]
+        except (KeyError, TypeError):
+            raise AttributeError("'%s' Model has no attribute '%s': %s"
+                % (self.__name__, name, self._values))
 
     def __contains__(self, name):
         return name in self._fields
diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py
index 068c567..50482de 100644
--- a/trytond/model/modelsql.py
+++ b/trytond/model/modelsql.py
@@ -13,7 +13,7 @@ from sql.aggregate import Count, Max
 from trytond.model import ModelStorage, ModelView
 from trytond.model import fields
 from trytond import backend
-from trytond.tools import reduce_ids, grouped_slice
+from trytond.tools import reduce_ids, grouped_slice, cursor_dict
 from trytond.const import OPERATORS
 from trytond.transaction import Transaction
 from trytond.pool import Pool
@@ -126,6 +126,8 @@ class ModelSQL(ModelStorage):
 
     @classmethod
     def __register__(cls, module_name):
+        sql_table = cls.__table__()
+        cursor = Transaction().connection.cursor()
         TableHandler = backend.get('TableHandler')
         super(ModelSQL, cls).__register__(module_name)
 
@@ -135,10 +137,9 @@ class ModelSQL(ModelStorage):
         pool = Pool()
 
         # create/update table in the database
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         if cls._history:
-            history_table = TableHandler(Transaction().cursor, cls,
-                    module_name, history=True)
+            history_table = TableHandler(cls, module_name, history=True)
             history_table.index_action('id', action='add')
 
         for field_name, field in cls._fields.iteritems():
@@ -205,17 +206,24 @@ class ModelSQL(ModelStorage):
             if isinstance(field, fields.Many2One) \
                     and field.model_name == cls.__name__ \
                     and field.left and field.right:
-                cls._rebuild_tree(field_name, None, 0)
+                left_default = cls._defaults.get(field.left, lambda: None)()
+                right_default = cls._defaults.get(field.right, lambda: None)()
+                cursor.execute(*sql_table.select(sql_table.id,
+                        where=(Column(sql_table, field.left) == left_default)
+                        | (Column(sql_table, field.left) == Null)
+                        | (Column(sql_table, field.right) == right_default)
+                        | (Column(sql_table, field.right) == Null),
+                        limit=1))
+                if cursor.fetchone():
+                    cls._rebuild_tree(field_name, None, 0)
 
         for ident, constraint, _ in cls._sql_constraints:
             table.add_constraint(ident, constraint)
 
         if cls._history:
             cls._update_history_table()
-            cursor = Transaction().cursor
-            table = cls.__table__()
             history_table = cls.__table_history__()
-            cursor.execute(*table.select(table.id))
+            cursor.execute(*sql_table.select(sql_table.id))
             if cursor.fetchone():
                 cursor.execute(*history_table.select(history_table.id))
                 if not cursor.fetchone():
@@ -223,7 +231,7 @@ class ModelSQL(ModelStorage):
                         if not hasattr(f, 'set')]
                     cursor.execute(*history_table.insert(
                             [Column(history_table, c) for c in columns],
-                            table.select(*(Column(table, c)
+                            sql_table.select(*(Column(sql_table, c)
                                     for c in columns))))
                     cursor.execute(*history_table.update(
                             [history_table.write_date], [None]))
@@ -232,9 +240,8 @@ class ModelSQL(ModelStorage):
     def _update_history_table(cls):
         TableHandler = backend.get('TableHandler')
         if cls._history:
-            table = TableHandler(Transaction().cursor, cls)
-            history_table = TableHandler(Transaction().cursor, cls,
-                    history=True)
+            table = TableHandler(cls)
+            history_table = TableHandler(cls, history=True)
             for column_name in table._columns:
                 string = ''
                 if column_name in cls._fields:
@@ -289,10 +296,10 @@ class ModelSQL(ModelStorage):
                     cls.raise_user_error('foreign_model_missing',
                         error_args=error_args)
         for name, _, error in cls._sql_constraints:
-            if name in str(exception[0]):
+            if name in str(exception):
                 cls.raise_user_error(error)
         for name, error in cls._sql_error_messages.iteritems():
-            if name in str(exception[0]):
+            if name in str(exception):
                 cls.raise_user_error(error)
 
     @classmethod
@@ -300,7 +307,7 @@ class ModelSQL(ModelStorage):
         pool = Pool()
         ModelAccess = pool.get('ir.model.access')
         User = pool.get('res.user')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
 
         ModelAccess.check(cls.__name__, 'read')
 
@@ -330,7 +337,7 @@ class ModelSQL(ModelStorage):
     @classmethod
     def __insert_history(cls, ids, deleted=False):
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         if not cls._history:
             return
         user = transaction.user
@@ -357,7 +364,7 @@ class ModelSQL(ModelStorage):
                 cursor.execute(*history.insert(hcolumns,
                         table.select(*columns, where=where)))
             else:
-                if cursor.has_multirow_insert():
+                if transaction.database.has_multirow_insert():
                     cursor.execute(*history.insert(hcolumns,
                             [[id_, CurrentTimestamp(), user]
                                 for id_ in sub_ids]))
@@ -371,7 +378,7 @@ class ModelSQL(ModelStorage):
         if not cls._history:
             return
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         table = cls.__table__()
         history = cls.__table_history__()
         columns = []
@@ -440,7 +447,7 @@ class ModelSQL(ModelStorage):
     @classmethod
     def __check_timestamp(cls, ids):
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         table = cls.__table__()
         if not transaction.timestamp:
             return
@@ -467,7 +474,7 @@ class ModelSQL(ModelStorage):
     def create(cls, vlist):
         DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         pool = Pool()
         Translation = pool.get('ir.translation')
         Rule = pool.get('ir.rule')
@@ -479,6 +486,7 @@ class ModelSQL(ModelStorage):
 
         table = cls.__table__()
         modified_fields = set()
+        defaults_cache = {}  # Store already computed default values
         new_ids = []
         vlist = [v.copy() for v in vlist]
         for values in vlist:
@@ -495,11 +503,16 @@ class ModelSQL(ModelStorage):
                 if (f not in values
                         and f not in ('create_uid', 'create_date',
                             'write_uid', 'write_date', 'id')):
-                    default.append(f)
+                    if f in defaults_cache:
+                        values[f] = defaults_cache[f]
+                    else:
+                        default.append(f)
 
             if default:
                 defaults = cls.default_get(default, with_rec_name=False)
-                values.update(cls._clean_defaults(defaults))
+                defaults = cls._clean_defaults(defaults)
+                values.update(defaults)
+                defaults_cache.update(defaults)
 
             insert_columns = [table.create_uid, table.create_date]
             insert_values = [transaction.user, CurrentTimestamp()]
@@ -512,12 +525,13 @@ class ModelSQL(ModelStorage):
                     insert_values.append(field.sql_format(value))
 
             try:
-                if cursor.has_returning():
+                if transaction.database.has_returning():
                     cursor.execute(*table.insert(insert_columns,
                             [insert_values], [table.id]))
                     id_new, = cursor.fetchone()
                 else:
-                    id_new = cursor.nextid(cls._table)
+                    id_new = transaction.database.nextid(
+                        transaction.connection, cls._table)
                     if id_new:
                         insert_columns.append(table.id)
                         insert_values.append(id_new)
@@ -526,10 +540,10 @@ class ModelSQL(ModelStorage):
                     else:
                         cursor.execute(*table.insert(insert_columns,
                                 [insert_values]))
-                        id_new = cursor.lastid()
+                        id_new = transaction.database.lastid(cursor)
                 new_ids.append(id_new)
             except DatabaseIntegrityError, exception:
-                with Transaction().new_cursor(), \
+                with Transaction().new_transaction(), \
                         Transaction().set_context(_check_access=False):
                     cls.__raise_integrity_error(exception, values)
                 raise
@@ -562,8 +576,14 @@ class ModelSQL(ModelStorage):
                     translation_values.setdefault(
                         '%s,%s' % (cls.__name__, fname), {})[new_id] = value
                 if hasattr(field, 'set'):
-                    fields_to_set.setdefault(fname, []).extend(
-                        ([new_id], value))
+                    args = fields_to_set.setdefault(fname, [])
+                    actions = iter(args)
+                    for ids, val in zip(actions, actions):
+                        if val == value:
+                            ids.append(new_id)
+                            break
+                    else:
+                        args.extend(([new_id], value))
 
         if translation_values:
             for name, translations in translation_values.iteritems():
@@ -599,7 +619,8 @@ class ModelSQL(ModelStorage):
                         mode='read'):
                     fields_names.append(field_name)
         super(ModelSQL, cls).read(ids, fields_names=fields_names)
-        cursor = Transaction().cursor
+        transaction = Transaction()
+        cursor = Transaction().connection.cursor()
 
         if not ids:
             return []
@@ -625,12 +646,12 @@ class ModelSQL(ModelStorage):
         table = cls.__table__()
         table_query = cls.table_query()
 
-        in_max = cursor.IN_MAX
+        in_max = transaction.database.IN_MAX
         history_order = None
         history_clause = None
         history_limit = None
         if (cls._history
-                and Transaction().context.get('_datetime')
+                and transaction.context.get('_datetime')
                 and not table_query):
             in_max = 1
             table = cls.__table_history__()
@@ -669,8 +690,8 @@ class ModelSQL(ModelStorage):
                     where &= dom_exp
                 cursor.execute(*from_.select(*columns, where=where,
                         order_by=history_order, limit=history_limit))
-                dictfetchall = cursor.dictfetchall()
-                if not len(dictfetchall) == len({}.fromkeys(sub_ids)):
+                fetchall = list(cursor_dict(cursor))
+                if not len(fetchall) == len({}.fromkeys(sub_ids)):
                     if domain:
                         where = red_sql
                         if history_clause:
@@ -684,7 +705,7 @@ class ModelSQL(ModelStorage):
                         if rowcount == len({}.fromkeys(sub_ids)):
                             cls.raise_user_error('access_error', cls.__name__)
                     cls.raise_user_error('read_error', cls.__name__)
-                result.extend(dictfetchall)
+                result.extend(fetchall)
         else:
             result = [{'id': x} for x in ids]
 
@@ -826,7 +847,7 @@ class ModelSQL(ModelStorage):
     def write(cls, records, values, *args):
         DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         pool = Pool()
         Translation = pool.get('ir.translation')
         Config = pool.get('ir.configuration')
@@ -903,8 +924,8 @@ class ModelSQL(ModelStorage):
                     cursor.execute(*table.update(columns, update_values,
                             where=red_sql))
                 except DatabaseIntegrityError, exception:
-                    with Transaction().new_cursor(), \
-                            Transaction().set_context(_check_access=False):
+                    with Transaction().new_transaction() as transaction, \
+                            transaction.set_context(_check_access=False):
                         cls.__raise_integrity_error(exception, values,
                             values.keys())
                     raise
@@ -936,7 +957,7 @@ class ModelSQL(ModelStorage):
     def delete(cls, records):
         DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
         pool = Pool()
         Translation = pool.get('ir.translation')
         Rule = pool.get('ir.rule')
@@ -1007,7 +1028,7 @@ class ModelSQL(ModelStorage):
                 if rowcount == -1 or rowcount is None:
                     rowcount = len(cursor.fetchall())
                 if not rowcount == len({}.fromkeys(sub_ids)):
-                    cls.raise_user_error('access_error', cls._get_name())
+                    cls.raise_user_error('access_error', cls.__name__)
 
         cls.trigger_delete(records)
 
@@ -1061,7 +1082,7 @@ class ModelSQL(ModelStorage):
             try:
                 cursor.execute(*table.delete(where=red_sql))
             except DatabaseIntegrityError, exception:
-                with Transaction().new_cursor():
+                with Transaction().new_transaction():
                     cls.__raise_integrity_error(exception, {})
                 raise
 
@@ -1077,7 +1098,7 @@ class ModelSQL(ModelStorage):
         pool = Pool()
         Rule = pool.get('ir.rule')
         transaction = Transaction()
-        cursor = transaction.cursor
+        cursor = transaction.connection.cursor()
 
         # Get domain clauses
         tables, expression = cls.search_domain(domain)
@@ -1137,8 +1158,8 @@ class ModelSQL(ModelStorage):
             return select
         cursor.execute(*select)
 
-        rows = cursor.dictfetchmany(cursor.IN_MAX)
-        cache = cursor.get_cache()
+        rows = list(cursor_dict(cursor, transaction.database.IN_MAX))
+        cache = transaction.get_cache()
         if cls.__name__ not in cache:
             cache[cls.__name__] = LRUDict(cache_size())
         delete_records = transaction.delete_records.setdefault(cls.__name__,
@@ -1186,7 +1207,7 @@ class ModelSQL(ModelStorage):
         # Can not cache the history value if we are not sure to have fetch all
         # the rows for each records
         if (not (cls._history and transaction.context.get('_datetime'))
-                or len(rows) < cursor.IN_MAX):
+                or len(rows) < transaction.database.IN_MAX):
             rows = list(filter_history(rows))
             keys = None
             for data in islice(rows, 0, cache.size_limit):
@@ -1206,9 +1227,9 @@ class ModelSQL(ModelStorage):
                     del data[k]
                 cache[cls.__name__].setdefault(data['id'], {}).update(data)
 
-        if len(rows) >= cursor.IN_MAX:
+        if len(rows) >= transaction.database.IN_MAX:
             if (cls._history
-                    and Transaction().context.get('_datetime')
+                    and transaction.context.get('_datetime')
                     and not query):
                 columns = columns[:3]
             else:
@@ -1216,7 +1237,7 @@ class ModelSQL(ModelStorage):
             cursor.execute(*table.select(*columns,
                     where=expression, order_by=order_by,
                     limit=limit, offset=offset))
-            rows = filter_history(cursor.dictfetchall())
+            rows = filter_history(list(cursor_dict(cursor)))
 
         return cls.browse([x['id'] for x in rows])
 
@@ -1269,8 +1290,7 @@ class ModelSQL(ModelStorage):
 
     @classmethod
     def _update_mptt(cls, field_names, list_ids, values=None):
-        cursor = Transaction().cursor
-        count = None
+        cursor = Transaction().connection.cursor()
         for field_name, ids in zip(field_names, list_ids):
             field = cls._fields[field_name]
             if (isinstance(field, fields.Many2One)
@@ -1294,11 +1314,7 @@ class ModelSQL(ModelStorage):
                         & (Column(parent, field.right) == 0)))
                 nested_create = cursor.fetchone()
 
-                if count is None:
-                    cursor.execute(*table.select(Count(Literal(1))))
-                    count, = cursor.fetchone()
-
-                if not nested_create and len(ids) < count / 4:
+                if not nested_create and len(ids) < 2:
                     for id_ in ids:
                         cls._update_tree(id_, field_name,
                             field.left, field.right)
@@ -1310,7 +1326,7 @@ class ModelSQL(ModelStorage):
         '''
         Rebuild left, right value for the tree.
         '''
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         right = left + 1
 
@@ -1338,7 +1354,7 @@ class ModelSQL(ModelStorage):
             - the value (right - left - 1) / 2 will not give
                 the number of children node
         '''
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         left = Column(table, left)
         right = Column(table, right)
@@ -1392,8 +1408,9 @@ class ModelSQL(ModelStorage):
     @classmethod
     def validate(cls, records):
         super(ModelSQL, cls).validate(records)
-        cursor = Transaction().cursor
-        if cursor.has_constraint():
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
+        if transaction.database.has_constraint():
             return
         # Works only for a single transaction
         ids = map(int, records)
@@ -1402,7 +1419,7 @@ class ModelSQL(ModelStorage):
             if isinstance(sql, Unique):
                 columns = [Column(table, c.name) for c in sql.columns]
                 columns.insert(0, table.id)
-                in_max = cursor.IN_MAX / (len(columns) + 1)
+                in_max = transaction.database.IN_MAX // (len(columns) + 1)
                 for sub_ids in grouped_slice(ids, in_max):
                     red_sql = reduce_ids(table.id, sub_ids)
 
diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py
index 0d447dc..4269278 100644
--- a/trytond/model/modelstorage.py
+++ b/trytond/model/modelstorage.py
@@ -5,10 +5,6 @@ import datetime
 import time
 import csv
 import warnings
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
 
 from decimal import Decimal
 from itertools import islice, ifilter, chain, izip
@@ -25,7 +21,7 @@ from trytond.const import OPERATORS
 from trytond.config import config
 from trytond.transaction import Transaction
 from trytond.pool import Pool
-from trytond.cache import LRUDict, freeze
+from trytond.cache import LRUDict, LRUDictTransaction, freeze
 from trytond import backend
 from trytond.rpc import RPC
 from .modelview import ModelView
@@ -170,8 +166,8 @@ class ModelStorage(Model):
             if local_cache:
                 local_cache.clear()
 
-        # Clean cursor cache
-        for cache in Transaction().cursor.cache.itervalues():
+        # Clean transaction cache
+        for cache in Transaction().cache.itervalues():
             if cls.__name__ in cache:
                 for record in all_records:
                     if record.id in cache[cls.__name__]:
@@ -224,8 +220,8 @@ class ModelStorage(Model):
         # Increase transaction counter
         Transaction().counter += 1
 
-        # Clean cursor cache
-        for cache in Transaction().cursor.cache.values():
+        # Clean transaction cache
+        for cache in Transaction().cache.values():
             for cache in (cache, cache.get('_language_cache', {}).values()):
                 if cls.__name__ in cache:
                     for record in records:
@@ -454,9 +450,14 @@ class ModelStorage(Model):
         '''
         Return a list of instance for the ids
         '''
+        transaction = Transaction()
         ids = map(int, ids)
-        local_cache = LRUDict(cache_size())
-        return [cls(int(x), _ids=ids, _local_cache=local_cache) for x in ids]
+        local_cache = LRUDictTransaction(cache_size())
+        transaction_cache = transaction.get_cache()
+        return [cls(x, _ids=ids,
+                _local_cache=local_cache,
+                _transaction_cache=transaction_cache,
+                _transaction=transaction) for x in ids]
 
     @staticmethod
     def __export_row(record, fields_names):
@@ -569,7 +570,7 @@ class ModelStorage(Model):
                 return None
             res = []
             Relation = pool.get(relation)
-            for word in csv.reader(StringIO.StringIO(value), delimiter=',',
+            for word in csv.reader(value.splitlines(), delimiter=',',
                     quoting=csv.QUOTE_NONE, escapechar='\\').next():
                 res2 = Relation.search([
                     ('rec_name', '=', word),
@@ -618,7 +619,7 @@ class ModelStorage(Model):
             relation = None
             ftype = fields_def[field[-1][:-3]]['type']
             if ftype == 'many2many':
-                value = csv.reader(StringIO.StringIO(value), delimiter=',',
+                value = csv.reader(value.splitlines(), delimiter=',',
                         quoting=csv.QUOTE_NONE, escapechar='\\').next()
             elif ftype == 'reference':
                 try:
@@ -785,7 +786,7 @@ class ModelStorage(Model):
             if values is None:
                 return False
             for model_data in models_data:
-                if not model_data.values:
+                if not model_data.values or model_data.noupdate:
                     continue
                 xml_values = ModelData.load_values(model_data.values)
                 for key, val in values.iteritems():
@@ -1136,6 +1137,8 @@ class ModelStorage(Model):
         pool = Pool()
         vals = {}
         for field in defaults.keys():
+            if '.' in field:  # skip all related fields
+                continue
             fld_def = cls._fields[field]
             if fld_def._type in ('many2one', 'one2one'):
                 if isinstance(defaults[field], (list, tuple)):
@@ -1159,9 +1162,13 @@ class ModelStorage(Model):
     def __init__(self, id=None, **kwargs):
         _ids = kwargs.pop('_ids', None)
         _local_cache = kwargs.pop('_local_cache', None)
-        self._cursor = Transaction().cursor
-        self._user = Transaction().user
-        self._context = Transaction().context
+        _transaction_cache = kwargs.pop('_transaction_cache', None)
+        transaction = kwargs.pop('_transaction', None)
+        if transaction is None:
+            transaction = Transaction()
+        self._transaction = transaction
+        self._user = transaction.user
+        self._context = transaction.context
         if id is not None:
             id = int(id)
         if _ids is not None:
@@ -1170,19 +1177,22 @@ class ModelStorage(Model):
         else:
             self._ids = [id]
 
-        self._cursor_cache = self._cursor.get_cache()
+        if _transaction_cache is not None:
+            self._transaction_cache = _transaction_cache
+        else:
+            self._transaction_cache = transaction.get_cache()
 
         if _local_cache is not None:
+            assert isinstance(_local_cache, LRUDictTransaction)
             self._local_cache = _local_cache
         else:
-            self._local_cache = LRUDict(cache_size())
-        self._local_cache.counter = Transaction().counter
+            self._local_cache = LRUDictTransaction(cache_size())
 
         super(ModelStorage, self).__init__(id, **kwargs)
 
     @property
     def _cache(self):
-        cache = self._cursor_cache
+        cache = self._transaction_cache
         if self.__name__ not in cache:
             cache[self.__name__] = LRUDict(cache_size())
         return cache[self.__name__]
@@ -1191,13 +1201,10 @@ class ModelStorage(Model):
         try:
             return super(ModelStorage, self).__getattr__(name)
         except AttributeError:
-            if self.id < 0:
+            if self.id is None or self.id < 0:
                 raise
 
-        counter = Transaction().counter
-        if self._local_cache.counter != counter:
-            self._local_cache.clear()
-            self._local_cache.counter = counter
+        self._local_cache.refresh()
 
         # fetch the definition of the field
         try:
@@ -1279,7 +1286,8 @@ class ModelStorage(Model):
         index = self._ids.index(self.id)
         ids = chain(islice(self._ids, index, None),
             islice(self._ids, 0, max(index - 1, 0)))
-        ids = islice(unique(ifilter(filter_, ids)), self._cursor.IN_MAX)
+        ids = islice(unique(ifilter(filter_, ids)),
+            self._transaction.database.IN_MAX)
 
         def instantiate(field, value, data):
             if field._type in ('many2one', 'one2one', 'reference'):
@@ -1300,6 +1308,7 @@ class ModelStorage(Model):
                     Model = field.get_target()
             except KeyError:
                 return value
+            transaction = Transaction()
             ctx = {}
             if field.context:
                 pyson_context = PYSONEncoder().encode(field.context)
@@ -1308,30 +1317,33 @@ class ModelStorage(Model):
             if getattr(field, 'datetime_field', None):
                 datetime_ = data.get(field.datetime_field)
                 ctx = {'_datetime': datetime_}
-            with Transaction().set_context(**ctx):
+            with transaction.set_context(**ctx):
+                kwargs = {}
                 key = (Model, freeze(ctx))
-                local_cache = model2cache.setdefault(key,
-                    LRUDict(cache_size()))
-                ids = model2ids.setdefault(key, [])
+                kwargs['_local_cache'] = model2cache.setdefault(key,
+                    LRUDictTransaction(cache_size()))
+                kwargs['_ids'] = ids = model2ids.setdefault(key, [])
+                kwargs['_transaction_cache'] = transaction.get_cache()
+                kwargs['_transaction'] = transaction
                 if field._type in ('many2one', 'one2one', 'reference'):
+                    value = int(value)
                     ids.append(value)
-                    return Model(value, _ids=ids, _local_cache=local_cache)
+                    return Model(value, **kwargs)
                 elif field._type in ('one2many', 'many2many'):
-                    ids.extend(value)
-                    return tuple(Model(id, _ids=ids, _local_cache=local_cache)
-                        for id in value)
+                    ids.extend(int(x) for x in value)
+                    return tuple(Model(id, **kwargs) for id in value)
 
         model2ids = {}
         model2cache = {}
         # Read the data
-        with Transaction().set_cursor(self._cursor), \
-                Transaction().set_user(self._user), \
-                Transaction().set_context(self._context):
+        with Transaction().set_current_transaction(self._transaction), \
+                self._transaction.set_user(self._user), \
+                self._transaction.set_context(self._context):
             if self.id in self._cache and name in self._cache[self.id]:
                 # Use values from cache
                 ids = islice(chain(islice(self._ids, index, None),
                         islice(self._ids, 0, max(index - 1, 0))),
-                    self._cursor.IN_MAX)
+                    self._transaction.database.IN_MAX)
                 ffields = {name: ffields[name]}
                 read_data = [{'id': i, name: self._cache[i][name]}
                     for i in ids
@@ -1373,7 +1385,8 @@ class ModelStorage(Model):
             field = self._fields[fname]
             if field._type in ('many2one', 'one2one', 'reference'):
                 if value:
-                    if value.id < 0 and field._type != 'reference':
+                    if ((value.id is None or value.id < 0)
+                            and field._type != 'reference'):
                         value.save()
                     if field._type == 'reference':
                         value = str(value)
@@ -1381,7 +1394,7 @@ class ModelStorage(Model):
                         value = value.id
             if field._type in ('one2many', 'many2many'):
                 targets = value
-                if self.id >= 0:
+                if self.id is not None and self.id >= 0:
                     _values, self._values = self._values, None
                     try:
                         to_remove = [t.id for t in getattr(self, fname)]
@@ -1393,7 +1406,7 @@ class ModelStorage(Model):
                 to_create = []
                 to_write = []
                 for target in targets:
-                    if target.id < 0:
+                    if target.id is None or target.id < 0:
                         if field._type == 'one2many':
                             # Don't store old target link
                             setattr(target, field.field, None)
@@ -1427,11 +1440,11 @@ class ModelStorage(Model):
         save_values = {}
         to_create = []
         to_write = []
-        cursor = records[0]._cursor
+        transaction = records[0]._transaction
         user = records[0]._user
         context = records[0]._context
         for record in records:
-            assert cursor == record._cursor
+            assert transaction == record._transaction
             assert user == record._user
             assert context == record._context
             save_values[record] = record._save_values
@@ -1443,14 +1456,14 @@ class ModelStorage(Model):
                 to_write.append(record)
         transaction = Transaction()
         try:
-            with transaction.set_cursor(cursor), \
+            with transaction.set_current_transaction(transaction), \
                     transaction.set_user(user), \
                     transaction.set_context(context):
                 if to_create:
                     news = cls.create([save_values[r] for r in to_create])
                     for record, new in izip(to_create, news):
                         record._ids.remove(record.id)
-                        record.id = new.id
+                        record._id = new.id
                         record._ids.append(record.id)
                 if to_write:
                     cls.write(*sum(
diff --git a/trytond/model/modelview.py b/trytond/model/modelview.py
index 4e709fb..d88aed7 100644
--- a/trytond/model/modelview.py
+++ b/trytond/model/modelview.py
@@ -25,20 +25,18 @@ def _find(tree, element):
     return None
 
 
-def _inherit_apply(src, inherit):
-    tree_src = etree.fromstring(src)
-    tree_inherit = etree.fromstring(inherit)
-    root_inherit = tree_inherit.getroottree().getroot()
+def _inherit_apply(tree, inherit):
+    root_inherit = inherit.getroottree().getroot()
     for element2 in root_inherit:
         if element2.tag != 'xpath':
             continue
-        element = _find(tree_src, element2)
+        element = _find(tree, element2)
         if element is not None:
             pos = element2.get('position', 'inside')
             if pos == 'replace':
                 parent = element.getparent()
                 if parent is None:
-                    tree_src, = element2
+                    tree, = element2
                     continue
                 enext = element.getnext()
                 if enext is not None:
@@ -75,7 +73,7 @@ def _inherit_apply(src, inherit):
             raise AttributeError(
                 'Couldn\'t find tag (%s: %s) in parent view!'
                 % (element2.tag, element2.get('expr')))
-    return etree.tostring(tree_src, encoding='utf-8')
+    return tree
 
 
 def on_change(func):
@@ -243,13 +241,13 @@ class ModelView(Model):
         else:
             domain = [
                 ('model', '=', cls.__name__),
-                ('type', '=', view_type),
                 ['OR',
                     ('inherit', '=', None),
                     ('inherit.model', '!=', cls.__name__),
                     ],
                 ]
             views = View.search(domain)
+            views = filter(lambda v: v.rng_type == view_type, views)
             if views:
                 view = views[0]
         if view:
@@ -260,7 +258,7 @@ class ModelView(Model):
 
         # if a view was found
         if view:
-            result['type'] = view.type
+            result['type'] = view.rng_type
             result['view_id'] = view_id
             result['arch'] = view.arch
             result['field_childs'] = view.field_childs
@@ -294,6 +292,8 @@ class ModelView(Model):
                     # There is perhaps a new module in the directory
                     ModelView._reset_modules_list()
                     raise_p = True
+            parser = etree.XMLParser(remove_comments=True)
+            tree = etree.fromstring(result['arch'], parser=parser)
             for view in views:
                 if view.domain:
                     if not PYSONDecoder({'context': Transaction().context}
@@ -301,7 +301,10 @@ class ModelView(Model):
                         continue
                 if not view.arch or not view.arch.strip():
                     continue
-                result['arch'] = _inherit_apply(result['arch'], view.arch)
+                tree_inherit = etree.fromstring(view.arch, parser=parser)
+                tree = _inherit_apply(tree, tree_inherit)
+            result['arch'] = etree.tostring(
+                tree, encoding='utf-8').decode('utf-8')
 
         # otherwise, build some kind of default view
         else:
@@ -429,8 +432,11 @@ class ModelView(Model):
                     parent.remove(element)
                 elif type == 'form':
                     element.tag = 'label'
+                    colspan = element.attrib.get('colspan')
                     element.attrib.clear()
                     element.attrib['id'] = 'hidden %s-%s' % (field, i)
+                    if colspan is not None:
+                        element.attrib['colspan'] = colspan
 
         if type == 'tree':
             ViewTreeWidth = pool.get('ir.ui.view_tree_width')
@@ -463,7 +469,8 @@ class ModelView(Model):
         if 'active' in cls._fields:
             fields_def.setdefault('active', {'name': 'active'})
 
-        arch = etree.tostring(tree, encoding='utf-8', pretty_print=False)
+        arch = etree.tostring(
+            tree, encoding='utf-8', pretty_print=False).decode('utf-8')
         fields2 = cls.fields_get(fields_def.keys())
         for field in fields_def:
             if field in fields2:
@@ -485,59 +492,64 @@ class ModelView(Model):
             fields_attrs = {}
         else:
             fields_attrs = copy.deepcopy(fields_attrs)
-        childs = True
 
-        if element.tag in ('field', 'label', 'separator', 'group', 'suffix',
-                'prefix'):
-            for attr in ('name', 'icon'):
-                if element.get(attr):
-                    fields_attrs.setdefault(element.get(attr), {})
-                    if type != 'form':
-                        continue
+        def set_view_ids(element):
+            view_ids = []
+            if element.get('view_ids'):
+                for view_id in element.get('view_ids').split(','):
                     try:
-                        field = cls._fields[element.get(attr)]
-                        if hasattr(field, 'model_name'):
-                            relation = field.model_name
-                        else:
-                            relation = field.get_target().__name__
-                    except Exception:
-                        relation = False
-                    if relation and element.tag == 'field':
-                        childs = False
-                        views = {}
-                        mode = (element.attrib.pop('mode', None)
-                            or 'tree,form').split(',')
-                        view_ids = []
-                        if element.get('view_ids'):
-                            for view_id in element.get('view_ids').split(','):
-                                try:
-                                    view_ids.append(int(view_id))
-                                except ValueError:
-                                    view_ids.append(ModelData.get_id(
-                                            *view_id.split('.')))
-                        Relation = pool.get(relation)
-                        if (not len(element)
-                                and type == 'form'
-                                and field._type in ('one2many', 'many2many')):
-                            # Prefetch only the first view to prevent infinite
-                            # loop
-                            if view_ids:
-                                for view_id in view_ids:
-                                    view = Relation.fields_view_get(
-                                        view_id=view_id)
-                                    views[str(view_id)] = view
-                                    break
-                            else:
-                                for view_type in mode:
-                                    views[view_type] = \
-                                        Relation.fields_view_get(
-                                            view_type=view_type)
-                                    break
-                        element.attrib['mode'] = ','.join(mode)
-                        element.attrib['view_ids'] = ','.join(
-                            map(str, view_ids))
-                        fields_attrs[element.get(attr)].setdefault('views', {}
-                            ).update(views)
+                        view_ids.append(int(view_id))
+                    except ValueError:
+                        view_ids.append(ModelData.get_id(*view_id.split('.')))
+                element.attrib['view_ids'] = ','.join(map(str, view_ids))
+            return view_ids
+
+        def get_relation(field):
+            if hasattr(field, 'model_name'):
+                return field.model_name
+            elif hasattr(field, 'get_target'):
+                return field.get_target().__name__
+
+        def get_views(relation, view_ids, mode):
+            Relation = pool.get(relation)
+            views = {}
+            if field._type in ['one2many', 'many2many']:
+                # Prefetch only the first view to prevent infinite loop
+                if view_ids:
+                    for view_id in view_ids:
+                        view = Relation.fields_view_get(view_id=view_id)
+                        views[str(view_id)] = view
+                        break
+                else:
+                    for view_type in mode:
+                        views[view_type] = (
+                            Relation.fields_view_get(view_type=view_type))
+                        break
+            return views
+
+        for attr in ('name', 'icon'):
+            if not element.get(attr):
+                continue
+            fields_attrs.setdefault(element.get(attr), {})
+
+        if element.tag == 'field' and type in ['tree', 'form']:
+            for attr in ('name', 'icon'):
+                fname = element.get(attr)
+                if not fname:
+                    continue
+                view_ids = set_view_ids(element)
+                if type != 'form':
+                    continue
+                field = cls._fields[fname]
+                relation = get_relation(field)
+                if not relation:
+                    continue
+                mode = (
+                    element.attrib.pop('mode', None) or 'tree,form').split(',')
+                views = get_views(relation, view_ids, mode)
+                element.attrib['mode'] = ','.join(mode)
+                fields_attrs[fname].setdefault('views', {}).update(views)
+
             if type == 'tree' and element.get('name') in fields_width:
                 element.set('width', str(fields_width[element.get('name')]))
 
@@ -585,10 +597,9 @@ class ModelView(Model):
                 if element.get(attr):
                     fields_attrs.setdefault(element.get(attr), {})
 
-        if childs:
-            for field in element:
-                fields_attrs = cls.__view_look_dom(field, type,
-                    fields_width=fields_width, fields_attrs=fields_attrs)
+        for field in element:
+            fields_attrs = cls.__view_look_dom(field, type,
+                fields_width=fields_width, fields_attrs=fields_attrs)
         return fields_attrs
 
     @staticmethod
diff --git a/trytond/model/workflow.py b/trytond/model/workflow.py
index 5d79934..940eec9 100644
--- a/trytond/model/workflow.py
+++ b/trytond/model/workflow.py
@@ -1,5 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+from collections import OrderedDict
 from functools import wraps
 
 
@@ -20,7 +21,7 @@ class Workflow(object):
             @wraps(func)
             def wrapper(cls, records, *args, **kwargs):
                 filtered = []
-                to_update = {}
+                to_update = OrderedDict()
 
                 for record in records:
                     current_state = getattr(record, cls._transition_state)
@@ -36,7 +37,7 @@ class Workflow(object):
                         current_state = getattr(record, cls._transition_state)
                         if current_state != to_update[record]:
                             del to_update[record]
-                    cls.write(to_update.keys(), {
+                    cls.write(list(to_update), {
                             cls._transition_state: state,
                             })
                 return result
diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py
index 1a78cea..9a453ef 100644
--- a/trytond/modules/__init__.py
+++ b/trytond/modules/__init__.py
@@ -205,92 +205,99 @@ def load_module_graph(graph, pool, update=None, lang=None):
         update = []
     modules_todo = []
     models_to_update_history = set()
-    cursor = Transaction().cursor
 
-    modules = [x.name for x in graph]
-    cursor.execute(*ir_module.select(ir_module.name, ir_module.state,
-            where=ir_module.name.in_(modules)))
-    module2state = dict(cursor.fetchall())
+    with Transaction().connection.cursor() as cursor:
+        modules = [x.name for x in graph]
+        cursor.execute(*ir_module.select(ir_module.name, ir_module.state,
+                where=ir_module.name.in_(modules)))
+        module2state = dict(cursor.fetchall())
 
-    for package in graph:
-        module = package.name
-        if module not in MODULES:
-            continue
-        logger.info(module)
-        classes = pool.setup(module)
-        package_state = module2state.get(module, 'uninstalled')
-        if (is_module_to_install(module, update)
-                or package_state in ('to install', 'to upgrade')):
-            if package_state not in ('to install', 'to upgrade'):
-                if package_state == 'installed':
-                    package_state = 'to upgrade'
-                elif package_state != 'to remove':
-                    package_state = 'to install'
-            for child in package.childs:
-                module2state[child.name] = package_state
-            for type in classes.keys():
-                for cls in classes[type]:
-                    logger.info('%s:register %s', module, cls.__name__)
-                    cls.__register__(module)
-            for model in classes['model']:
-                if hasattr(model, '_history'):
-                    models_to_update_history.add(model.__name__)
-
-            # Instanciate a new parser for the package:
-            tryton_parser = convert.TrytondXmlHandler(pool=pool, module=module,
-                module_state=package_state)
-
-            for filename in package.info.get('xml', []):
-                filename = filename.replace('/', os.sep)
-                logger.info('%s:loading %s', module, filename)
-                # Feed the parser with xml content:
-                with tools.file_open(OPJ(module, filename)) as fp:
-                    tryton_parser.parse_xmlstream(fp)
-
-            modules_todo.append((module, list(tryton_parser.to_delete)))
-
-            localedir = '%s/%s' % (package.info['directory'], 'locale')
-            for filename in itertools.chain(
-                    iglob('%s/*.po' % localedir),
-                    iglob('%s/override/*.po' % localedir)):
-                filename = filename.replace('/', os.sep)
-                lang2 = os.path.splitext(os.path.basename(filename))[0]
-                if lang2 not in lang:
-                    continue
-                logger.info('%s:loading %s', module,
-                    filename[len(package.info['directory']) + 1:])
-                Translation = pool.get('ir.translation')
-                Translation.translation_import(lang2, module, filename)
-
-            if package_state == 'to remove':
+        for package in graph:
+            module = package.name
+            if module not in MODULES:
                 continue
-            cursor.execute(*ir_module.select(ir_module.id,
-                    where=(ir_module.name == package.name)))
-            try:
-                module_id, = cursor.fetchone()
-                cursor.execute(*ir_module.update([ir_module.state],
-                        ['installed'], where=(ir_module.id == module_id)))
-            except TypeError:
-                cursor.execute(*ir_module.insert(
-                        [ir_module.create_uid, ir_module.create_date,
-                            ir_module.name, ir_module.state],
-                        [[0, CurrentTimestamp(), package.name, 'installed']]))
-            module2state[package.name] = 'installed'
-
-        cursor.commit()
-
-    for model_name in models_to_update_history:
-        model = pool.get(model_name)
-        if model._history:
-            logger.info('history:update %s', model.__name__)
-            model._update_history_table()
-
-    # Vacuum :
-    while modules_todo:
-        (module, to_delete) = modules_todo.pop()
-        convert.post_import(pool, module, to_delete)
-
-    cursor.commit()
+            logger.info(module)
+            classes = pool.fill(module)
+            if update:
+                pool.setup(classes)
+            package_state = module2state.get(module, 'uninstalled')
+            if (is_module_to_install(module, update)
+                    or (update
+                        and package_state in ('to install', 'to upgrade'))):
+                if package_state not in ('to install', 'to upgrade'):
+                    if package_state == 'installed':
+                        package_state = 'to upgrade'
+                    elif package_state != 'to remove':
+                        package_state = 'to install'
+                for child in package.childs:
+                    module2state[child.name] = package_state
+                for type in classes.keys():
+                    for cls in classes[type]:
+                        logger.info('%s:register %s', module, cls.__name__)
+                        cls.__register__(module)
+                for model in classes['model']:
+                    if hasattr(model, '_history'):
+                        models_to_update_history.add(model.__name__)
+
+                # Instanciate a new parser for the package:
+                tryton_parser = convert.TrytondXmlHandler(pool=pool,
+                    module=module, module_state=package_state)
+
+                for filename in package.info.get('xml', []):
+                    filename = filename.replace('/', os.sep)
+                    logger.info('%s:loading %s', module, filename)
+                    # Feed the parser with xml content:
+                    with tools.file_open(OPJ(module, filename), 'rb') as fp:
+                        tryton_parser.parse_xmlstream(fp)
+
+                modules_todo.append((module, list(tryton_parser.to_delete)))
+
+                localedir = '%s/%s' % (package.info['directory'], 'locale')
+                for filename in itertools.chain(
+                        iglob('%s/*.po' % localedir),
+                        iglob('%s/override/*.po' % localedir)):
+                    filename = filename.replace('/', os.sep)
+                    lang2 = os.path.splitext(os.path.basename(filename))[0]
+                    if lang2 not in lang:
+                        continue
+                    logger.info('%s:loading %s', module,
+                        filename[len(package.info['directory']) + 1:])
+                    Translation = pool.get('ir.translation')
+                    Translation.translation_import(lang2, module, filename)
+
+                if package_state == 'to remove':
+                    continue
+                cursor.execute(*ir_module.select(ir_module.id,
+                        where=(ir_module.name == package.name)))
+                try:
+                    module_id, = cursor.fetchone()
+                    cursor.execute(*ir_module.update([ir_module.state],
+                            ['installed'], where=(ir_module.id == module_id)))
+                except TypeError:
+                    cursor.execute(*ir_module.insert(
+                            [ir_module.create_uid, ir_module.create_date,
+                                ir_module.name, ir_module.state],
+                            [[0, CurrentTimestamp(), package.name,
+                                    'installed'],
+                                ]))
+                module2state[package.name] = 'installed'
+
+            Transaction().connection.commit()
+
+        if not update:
+            pool.setup()
+
+        for model_name in models_to_update_history:
+            model = pool.get(model_name)
+            if model._history:
+                logger.info('history:update %s', model.__name__)
+                model._update_history_table()
+
+        # Vacuum :
+        while modules_todo:
+            (module, to_delete) = modules_todo.pop()
+            convert.post_import(pool, module, to_delete)
+    logger.info('all modules loaded')
 
 
 def get_module_list():
@@ -307,7 +314,6 @@ def get_module_list():
     module_list.update(EGG_MODULES.keys())
     module_list.add('ir')
     module_list.add('res')
-    module_list.add('webdav')
     module_list.add('tests')
     return list(module_list)
 
@@ -320,8 +326,6 @@ def register_classes():
     trytond.ir.register()
     import trytond.res
     trytond.res.register()
-    import trytond.webdav
-    trytond.webdav.register()
     import trytond.tests
     trytond.tests.register()
 
@@ -329,7 +333,7 @@ def register_classes():
         module = package.name
         logger.info('%s:registering classes', module)
 
-        if module in ('ir', 'res', 'webdav', 'tests'):
+        if module in ('ir', 'res', 'tests'):
             MODULES.append(module)
             continue
 
@@ -370,63 +374,61 @@ def load_modules(database_name, pool, update=None, lang=None):
     def _load_modules():
         global res
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
-
-        # Migration from 3.6: remove double module
-        old_table = 'ir_module_module'
-        new_table = 'ir_module'
-        if TableHandler.table_exist(cursor, old_table):
-            TableHandler.table_rename(cursor, old_table, new_table)
-        if update:
-            cursor.execute(*ir_module.select(ir_module.name,
-                    where=ir_module.state.in_(('installed', 'to install',
-                            'to upgrade', 'to remove'))))
-        else:
-            cursor.execute(*ir_module.select(ir_module.name,
-                    where=ir_module.state.in_(('installed', 'to upgrade',
-                            'to remove'))))
-        module_list = [name for (name,) in cursor.fetchall()]
-        if update:
-            module_list += update
-        graph = create_graph(module_list)[0]
-
-        try:
+        transaction = Transaction()
+
+        with transaction.connection.cursor() as cursor:
+            # Migration from 3.6: remove double module
+            old_table = 'ir_module_module'
+            new_table = 'ir_module'
+            if TableHandler.table_exist(old_table):
+                TableHandler.table_rename(old_table, new_table)
+            if update:
+                cursor.execute(*ir_module.select(ir_module.name,
+                        where=ir_module.state.in_(('installed', 'to install',
+                                'to upgrade', 'to remove'))))
+            else:
+                cursor.execute(*ir_module.select(ir_module.name,
+                        where=ir_module.state.in_(('installed', 'to upgrade',
+                                'to remove'))))
+            module_list = [name for (name,) in cursor.fetchall()]
+            if update:
+                module_list += update
+            graph = create_graph(module_list)[0]
+
             load_module_graph(graph, pool, update, lang)
-        except Exception:
-            cursor.rollback()
-            raise
-
-        if update:
-            cursor.execute(*ir_module.select(ir_module.name,
-                    where=(ir_module.state == 'to remove')))
-            fetchall = cursor.fetchall()
-            if fetchall:
-                for (mod_name,) in fetchall:
-                    # TODO check if ressource not updated by the user
-                    cursor.execute(*ir_model_data.select(ir_model_data.model,
-                            ir_model_data.db_id,
-                            where=(ir_model_data.module == mod_name),
-                            order_by=ir_model_data.id.desc))
-                    for rmod, rid in cursor.fetchall():
-                        Model = pool.get(rmod)
-                        Model.delete([Model(rid)])
-                    cursor.commit()
-                cursor.execute(*ir_module.update([ir_module.state],
-                        ['uninstalled'],
-                        where=(ir_module.state == 'to remove')))
-                cursor.commit()
-                res = False
 
-            Module = pool.get('ir.module')
-            Module.update_list()
-        cursor.commit()
+            if update:
+                cursor.execute(*ir_module.select(ir_module.name,
+                        where=(ir_module.state == 'to remove')))
+                fetchall = cursor.fetchall()
+                if fetchall:
+                    for (mod_name,) in fetchall:
+                        # TODO check if ressource not updated by the user
+                        cursor.execute(*ir_model_data.select(
+                                ir_model_data.model, ir_model_data.db_id,
+                                where=(ir_model_data.module == mod_name),
+                                order_by=ir_model_data.id.desc))
+                        for rmod, rid in cursor.fetchall():
+                            Model = pool.get(rmod)
+                            Model.delete([Model(rid)])
+                        Transaction().connection.commit()
+                    cursor.execute(*ir_module.update([ir_module.state],
+                            ['uninstalled'],
+                            where=(ir_module.state == 'to remove')))
+                    Transaction().connection.commit()
+                    res = False
+
+                Module = pool.get('ir.module')
+                Module.update_list()
+        # Need to commit to unlock SQLite database
+        transaction.commit()
         Cache.resets(database_name)
 
-    if not Transaction().cursor:
+    if not Transaction().connection:
         with Transaction().start(database_name, 0):
             _load_modules()
     else:
-        with Transaction().new_cursor(), \
+        with Transaction().new_transaction(), \
                 Transaction().set_user(0), \
                 Transaction().reset_context():
             _load_modules()
diff --git a/trytond/monitor.py b/trytond/monitor.py
deleted file mode 100644
index 866d594..0000000
--- a/trytond/monitor.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import sys
-import os
-import subprocess
-from threading import Lock
-from trytond.modules import get_module_list
-
-_LOCK = Lock()
-_TIMES = {}
-_MODULES = None
-
-
-def _modified(path):
-    _LOCK.acquire()
-    try:
-        try:
-            if not os.path.isfile(path):
-                return path in _TIMES
-
-            mtime = os.stat(path).st_mtime
-            if path not in _TIMES:
-                _TIMES[path] = mtime
-
-            if mtime != _TIMES[path]:
-                _TIMES[path] = mtime
-                return True
-        except Exception:
-            return True
-    finally:
-        _LOCK.release()
-    return False
-
-
-def monitor(files):
-    '''
-    Monitor files and module files for change
-
-    :return: True if at least one file has changed
-    '''
-    global _MODULES
-    modified = False
-    for file_ in files:
-        if _modified(file_):
-            modified = True
-    directories = set()
-    for module in sys.modules.keys():
-        if not module.startswith('trytond.'):
-            continue
-        if not hasattr(sys.modules[module], '__file__'):
-            continue
-        path = getattr(sys.modules[module], '__file__')
-        if not path:
-            continue
-        if os.path.splitext(path)[1] in ['.pyc', '.pyo', '.pyd']:
-            path = path[:-1]
-        if _modified(path):
-            if subprocess.call((sys.executable, '-c', 'import %s' % module),
-                    cwd=os.path.dirname(os.path.abspath(os.path.normpath(
-                        os.path.join(__file__, '..'))))):
-                modified = False
-                break
-            modified = True
-
-        # Check view XML
-        directory = os.path.dirname(path)
-        if directory not in directories:
-            directories.add(directory)
-            view_dir = os.path.join(directory, 'view')
-            if os.path.isdir(view_dir):
-                for view in os.listdir(view_dir):
-                    view = os.path.join(view_dir, view)
-                    if os.path.splitext(view)[1] == '.xml':
-                        if _modified(view):
-                            modified = True
-
-    modules = set(get_module_list())
-    if _MODULES is None:
-        _MODULES = modules
-    for module in modules.difference(_MODULES):
-        if subprocess.call((sys.executable, '-c',
-                    'import trytond.modules.%s' % module)):
-            modified = False
-            break
-        modified = True
-    _MODULES = modules
-    return modified
diff --git a/trytond/pool.py b/trytond/pool.py
index 3ad6176..3b9a6ee 100644
--- a/trytond/pool.py
+++ b/trytond/pool.py
@@ -55,7 +55,7 @@ class Pool(object):
 
     def __new__(cls, database_name=None):
         if database_name is None:
-            database_name = Transaction().cursor.database_name
+            database_name = Transaction().database.name
         result = cls._instances.get(database_name)
         if result:
             return result
@@ -69,7 +69,7 @@ class Pool(object):
 
     def __init__(self, database_name=None):
         if database_name is None:
-            database_name = Transaction().cursor.database_name
+            database_name = Transaction().database.name
         self.database_name = database_name
 
     @staticmethod
@@ -196,10 +196,10 @@ class Pool(object):
         '''
         return self._pool[self.database_name][type].iteritems()
 
-    def setup(self, module):
+    def fill(self, module):
         '''
-        Setup classes for module and return a list of classes for each type in
-        a dictionary.
+        Fill the pool with the registered class from the module.
+        Return a list of classes for each type in a dictionary.
         '''
         classes = {}
         for type_ in self.classes.keys():
@@ -212,13 +212,22 @@ class Pool(object):
                     pass
                 if not issubclass(cls, PoolBase):
                     continue
-                cls.__setup__()
                 self.add(cls, type=type_)
                 classes[type_].append(cls)
-            for cls in classes[type_]:
-                cls.__post_setup__()
         return classes
 
+    def setup(self, classes=None):
+        logger.info('setup pool for "%s"', self.database_name)
+        if classes is None:
+            classes = {}
+            for type_ in self._pool[self.database_name]:
+                classes[type_] = self._pool[self.database_name][type_].values()
+        for type_, lst in classes.iteritems():
+            for cls in lst:
+                cls.__setup__()
+            for cls in lst:
+                cls.__post_setup__()
+
 
 def isregisteredby(obj, module, type_='model'):
     pool = Pool()
diff --git a/trytond/protocols/common.py b/trytond/protocols/common.py
deleted file mode 100644
index c38ac17..0000000
--- a/trytond/protocols/common.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import errno
-import os
-import socket
-import threading
-from SocketServer import StreamRequestHandler
-
-
-def endsocket(sock):
-    if os.name != 'nt':
-        try:
-            sock.shutdown(getattr(socket, 'SHUT_RDWR', 2))
-        except socket.error, e:
-            if e.errno != errno.ENOTCONN:
-                raise
-        sock.close()
-
-
-class daemon(threading.Thread):
-    def __init__(self, interface, port, secure, name=None):
-        threading.Thread.__init__(self, name=name)
-        self.secure = secure
-        self.ipv6 = False
-        for family, _, _, _, _ in socket.getaddrinfo(interface or None, port,
-                socket.AF_UNSPEC, socket.SOCK_STREAM):
-            if family == socket.AF_INET6:
-                self.ipv6 = True
-            break
-
-    def stop(self):
-        self.server.shutdown()
-        self.server.socket.shutdown(socket.SHUT_RDWR)
-        self.server.server_close()
-        return
-
-    def run(self):
-        self.server.serve_forever()
-        return True
-
-
-class RegisterHandlerMixin:
-
-    def setup(self):
-        self.server.handlers.add(self)
-        StreamRequestHandler.setup(self)
-
-    def finish(self):
-        StreamRequestHandler.finish(self)
-        try:
-            self.server.handlers.remove(self)
-        except KeyError:
-            pass
diff --git a/trytond/protocols/dispatcher.py b/trytond/protocols/dispatcher.py
index 4061fbf..7414ec3 100644
--- a/trytond/protocols/dispatcher.py
+++ b/trytond/protocols/dispatcher.py
@@ -4,7 +4,9 @@
 import logging
 import time
 import pydoc
+from functools import wraps
 
+from werkzeug.utils import redirect
 from sql import Table
 
 from trytond.pool import Pool
@@ -14,9 +16,9 @@ from trytond.config import config
 from trytond import __version__
 from trytond.transaction import Transaction
 from trytond.cache import Cache
-from trytond.exceptions import UserError, UserWarning, NotLogged, \
-    ConcurrencyException
+from trytond.exceptions import UserError, UserWarning, ConcurrencyException
 from trytond.tools import is_instance_method
+from trytond.wsgi import app
 
 logger = logging.getLogger(__name__)
 
@@ -26,133 +28,170 @@ ir_module = Table('ir_module')
 res_user = Table('res_user')
 
 
-def dispatch(host, port, protocol, database_name, user, session, object_type,
-        object_name, method, *args, **kwargs):
-    Database = backend.get('Database')
-    DatabaseOperationalError = backend.get('DatabaseOperationalError')
-    if object_type == 'common':
-        if method == 'login':
-            try:
-                database = Database(database_name).connect()
-                cursor = database.cursor()
-                cursor.close()
-            except Exception:
-                return False
-            res = security.login(database_name, user, session)
-            with Transaction().start(database_name, 0):
-                Cache.clean(database_name)
-                Cache.resets(database_name)
-            msg = res and 'successful login' or 'bad login or password'
-            logger.info('%s \'%s\' from %s:%d using %s on database \'%s\'',
-                msg, user, host, port, protocol, database_name)
-            return res or False
-        elif method == 'logout':
-            name = security.logout(database_name, user, session)
-            logger.info('logout \'%s\' from %s:%d '
-                'using %s on database \'%s\'',
-                name, host, port, protocol, database_name)
-            return True
-        elif method == 'version':
-            return __version__
-        elif method == 'list_lang':
-            return [
-                ('bg_BG', 'Български'),
-                ('ca_ES', 'Català'),
-                ('cs_CZ', 'Čeština'),
-                ('de_DE', 'Deutsch'),
-                ('en_US', 'English'),
-                ('es_AR', 'Español (Argentina)'),
-                ('es_EC', 'Español (Ecuador)'),
-                ('es_ES', 'Español (España)'),
-                ('es_CO', 'Español (Colombia)'),
-                ('es_MX', 'Español (México)'),
-                ('fr_FR', 'Français'),
-                ('hu_HU', 'Magyar'),
-                ('it_IT', 'Italiano'),
-                ('lt_LT', 'Lietuvių'),
-                ('nl_NL', 'Nederlands'),
-                ('pt_BR', 'Português (Brasil)'),
-                ('ru_RU', 'Russian'),
-                ('sl_SI', 'Slovenščina'),
-            ]
-        elif method == 'db_exist':
-            try:
-                database = Database(*args, **kwargs).connect()
-                cursor = database.cursor()
-                cursor.close(close=True)
-                return True
-            except Exception:
-                return False
-        elif method == 'list':
-            if not config.getboolean('database', 'list'):
-                raise Exception('AccessDenied')
-            with Transaction().start(None, 0, close=True) as transaction:
-                return transaction.database.list(transaction.cursor)
-        elif method == 'create':
-            return create(*args, **kwargs)
-        elif method == 'restore':
-            return restore(*args, **kwargs)
-        elif method == 'drop':
-            return drop(*args, **kwargs)
-        elif method == 'dump':
-            return dump(*args, **kwargs)
-        return
-    elif object_type == 'system':
-        database = Database(database_name).connect()
+def with_pool(func):
+    @wraps(func)
+    def wrapper(request, database_name, *args, **kwargs):
         database_list = Pool.database_list()
         pool = Pool(database_name)
         if database_name not in database_list:
-            pool.init()
-        if method == 'listMethods':
-            res = []
-            for type in ('model', 'wizard', 'report'):
-                for object_name, obj in pool.iterobject(type=type):
-                    for method in obj.__rpc__:
-                        res.append(type + '.' + object_name + '.' + method)
-            return res
-        elif method == 'methodSignature':
-            return 'signatures not supported'
-        elif method == 'methodHelp':
-            res = []
-            args_list = args[0].split('.')
-            object_type = args_list[0]
-            object_name = '.'.join(args_list[1:-1])
-            method = args_list[-1]
-            obj = pool.get(object_name, type=object_type)
-            return pydoc.getdoc(getattr(obj, method))
+            with Transaction().start(
+                    database_name, request.user_id, readonly=True):
+                pool.init()
+        return func(request, pool, *args, **kwargs)
+    return wrapper
 
-    for count in range(config.getint('database', 'retry'), -1, -1):
-        try:
-            user = security.check(database_name, user, session)
-        except DatabaseOperationalError:
-            if count:
-                continue
-            raise
-        break
 
-    database_list = Pool.database_list()
-    pool = Pool(database_name)
-    if database_name not in database_list:
-        with Transaction().start(database_name, user,
-                readonly=True) as transaction:
-            pool.init()
-    obj = pool.get(object_name, type=object_type)
+ at app.route('/<string:database_name>/', methods=['POST'])
+def rpc(request, database_name):
+    methods = {
+        'common.db.login': login,
+        'common.db.logout': logout,
+        'common.db.db_exist': db_exist,
+        'common.db.create': create,
+        'common.db.restore': restore,
+        'common.db.drop': drop,
+        'common.db.dump': dump,
+        'system.listMethods': list_method,
+        'system.methodHelp': help_method,
+        'system.methodSignature': lambda *a: 'signatures not supported',
+        }
+    return methods.get(request.method, _dispatch)(
+        request, database_name, *request.params)
+
+
+def login(request, database_name, user, password):
+    Database = backend.get('Database')
+    DatabaseOperationalError = backend.get('DatabaseOperationalError')
+    try:
+        Database(database_name).connect()
+    except DatabaseOperationalError:
+        logger.error('fail to connect to %s', database_name, exc_info=True)
+        return False
+    session = security.login(database_name, user, password)
+    with Transaction().start(database_name, 0):
+        Cache.clean(database_name)
+        Cache.resets(database_name)
+    msg = 'successful login' if session else 'bad login or password'
+    logger.info('%s \'%s\' from %s using %s on database \'%s\'',
+        msg, user, request.remote_addr, request.scheme, database_name)
+    return session
+
+
+ at app.auth_required
+def logout(request, database_name):
+    auth = request.authorization
+    name = security.logout(
+        database_name, auth.get('userid'), auth.get('session'))
+    logger.info('logout \'%s\' from %s using %s on database \'%s\'',
+        name, request.remote_addr, request.scheme, database_name)
+    return True
+
+
+ at app.route('/', methods=['POST'])
+def root(request, *args):
+    methods = {
+        'common.server.version': lambda *a: __version__,
+        'common.db.list_lang': list_lang,
+        'common.db.list': db_list,
+        }
+    return methods[request.method](request, *request.params)
+
+
+ at app.route('/', methods=['GET'])
+def home(request):
+    return redirect('/index.html')  # XXX find a better way
+
+
+def list_lang(*args):
+    return [
+        ('bg_BG', 'Български'),
+        ('ca_ES', 'Català'),
+        ('cs_CZ', 'Čeština'),
+        ('de_DE', 'Deutsch'),
+        ('en_US', 'English'),
+        ('es_AR', 'Español (Argentina)'),
+        ('es_EC', 'Español (Ecuador)'),
+        ('es_ES', 'Español (España)'),
+        ('es_CO', 'Español (Colombia)'),
+        ('es_MX', 'Español (México)'),
+        ('fr_FR', 'Français'),
+        ('hu_HU', 'Magyar'),
+        ('it_IT', 'Italiano'),
+        ('lt_LT', 'Lietuvių'),
+        ('lo_LA', 'ລາວ'),
+        ('nl_NL', 'Nederlands'),
+        ('pt_BR', 'Português (Brasil)'),
+        ('ru_RU', 'Russian'),
+        ('sl_SI', 'Slovenščina'),
+        ('zh_CN', '中国(简体)'),
+        ]
+
 
+def db_exist(request, database_name):
+    Database = backend.get('Database')
+    try:
+        Database(database_name).connect()
+        return True
+    except Exception:
+        return False
+
+
+def db_list(*args):
+    if not config.getboolean('database', 'list'):
+        raise Exception('AccessDenied')
+    with Transaction().start(None, 0, close=True) as transaction:
+        return transaction.database.list()
+
+
+ at app.auth_required
+ at with_pool
+def list_method(request, pool):
+    methods = []
+    for type in ('model', 'wizard', 'report'):
+        for object_name, obj in pool.iterobject(type=type):
+            for method in obj.__rpc__:
+                methods.append(type + '.' + object_name + '.' + method)
+    return methods
+
+
+def get_object_method(request, pool):
+    method = request.method
+    type, _ = method.split('.', 1)
+    name = '.'.join(method.split('.')[1:-1])
+    method = method.split('.')[-1]
+    return pool.get(name, type=type), method
+
+
+ at app.auth_required
+ at with_pool
+def help_method(request, pool):
+    obj, method = get_object_method(request, pool)
+    return pydoc.getdoc(getattr(obj, method))
+
+
+ at app.auth_required
+ at with_pool
+def _dispatch(request, pool, *args, **kwargs):
+    DatabaseOperationalError = backend.get('DatabaseOperationalError')
+
+    obj, method = get_object_method(request, pool)
     if method in obj.__rpc__:
         rpc = obj.__rpc__[method]
     else:
-        raise UserError('Calling method %s on %s %s is not allowed!'
-            % (method, object_type, object_name))
-
-    log_message = '%s.%s.%s(*%s, **%s) from %s@%s:%d/%s'
-    log_args = (object_type, object_name, method, args, kwargs,
-        user, host, port, database_name)
+        raise UserError('Calling method %s on %s is not allowed'
+            % (method, obj))
 
+    log_message = '%s.%s(*%s, **%s) from %s@%s/%s'
+    log_args = (obj, method, args, kwargs,
+        request.authorization.username, request.remote_addr, request.path)
     logger.info(log_message, *log_args)
+
+    user = request.user_id
+
     for count in range(config.getint('database', 'retry'), -1, -1):
-        with Transaction().start(database_name, user,
+        with Transaction().start(pool.database_name, user,
                 readonly=rpc.readonly) as transaction:
-            Cache.clean(database_name)
+            Cache.clean(pool.database_name)
             try:
                 c_args, c_kwargs, transaction.context, transaction.timestamp \
                     = rpc.convert(obj, *args, **kwargs)
@@ -168,38 +207,33 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
                     else:
                         result = [rpc.result(meth(i, *c_args, **c_kwargs))
                             for i in inst]
-                if not rpc.readonly:
-                    transaction.cursor.commit()
             except DatabaseOperationalError:
-                transaction.cursor.rollback()
                 if count and not rpc.readonly:
+                    transaction.rollback()
                     continue
+                logger.error(log_message, *log_args, exc_info=True)
                 raise
-            except (NotLogged, ConcurrencyException, UserError, UserWarning):
+            except (ConcurrencyException, UserError, UserWarning):
                 logger.debug(log_message, *log_args, exc_info=True)
-                transaction.cursor.rollback()
                 raise
             except Exception:
                 logger.error(log_message, *log_args, exc_info=True)
-                transaction.cursor.rollback()
                 raise
-            Cache.resets(database_name)
-        with Transaction().start(database_name, 0) as transaction:
-            pool = Pool(database_name)
-            Session = pool.get('ir.session')
+            # Need to commit to unlock SQLite database
+            transaction.commit()
+            Cache.resets(pool.database_name)
+        if request.authorization.type == 'session':
             try:
-                Session.reset(session)
+                with Transaction().start(pool.database_name, 0) as transaction:
+                    Session = pool.get('ir.session')
+                    Session.reset(request.authorization.get('session'))
             except DatabaseOperationalError:
                 logger.debug('Reset session failed', exc_info=True)
-                # Silently fail when reseting session
-                transaction.cursor.rollback()
-            else:
-                transaction.cursor.commit()
         logger.debug('Result: %s', result)
         return result
 
 
-def create(database_name, password, lang, admin_password):
+def create(request, database_name, password, lang, admin_password):
     '''
     Create a database
 
@@ -216,14 +250,13 @@ def create(database_name, password, lang, admin_password):
     try:
         with Transaction().start(None, 0, close=True, autocommit=True) \
                 as transaction:
-            transaction.database.create(transaction.cursor, database_name)
-            transaction.cursor.commit()
+            transaction.database.create(transaction.connection, database_name)
 
-        with Transaction().start(database_name, 0) as transaction:
-            Database.init(transaction.cursor)
-            transaction.cursor.execute(*ir_configuration.insert(
+        with Transaction().start(database_name, 0) as transaction,\
+                transaction.connection.cursor() as cursor:
+            Database(database_name).init()
+            cursor.execute(*ir_configuration.insert(
                     [ir_configuration.language], [[lang]]))
-            transaction.cursor.commit()
 
         pool = Pool(database_name)
         pool.init(update=['res', 'ir'], lang=[lang])
@@ -244,7 +277,6 @@ def create(database_name, password, lang, admin_password):
             Module = pool.get('ir.module')
             if Module:
                 Module.update_list()
-            transaction.cursor.commit()
             res = True
     except Exception:
         logger.error('CREATE DB: %s failed', database_name, exc_info=True)
@@ -254,19 +286,18 @@ def create(database_name, password, lang, admin_password):
     return res
 
 
-def drop(database_name, password):
+def drop(request, database_name, password):
     Database = backend.get('Database')
     security.check_super(password)
-    Database(database_name).close()
+    database = Database(database_name)
+    database.close()
     # Sleep to let connections close
     time.sleep(1)
 
     with Transaction().start(None, 0, close=True, autocommit=True) \
             as transaction:
-        cursor = transaction.cursor
         try:
-            Database.drop(cursor, database_name)
-            cursor.commit()
+            database.drop(transaction.connection, database_name)
         except Exception:
             logger.error('DROP DB: %s failed', database_name, exc_info=True)
             raise
@@ -277,7 +308,7 @@ def drop(database_name, password):
     return True
 
 
-def dump(database_name, password):
+def dump(request, database_name, password):
     Database = backend.get('Database')
     security.check_super(password)
     Database(database_name).close()
@@ -292,13 +323,11 @@ def dump(database_name, password):
         return bytes(data)
 
 
-def restore(database_name, password, data, update=False):
+def restore(request, database_name, password, data, update=False):
     Database = backend.get('Database')
     security.check_super(password)
     try:
-        database = Database(database_name).connect()
-        cursor = database.cursor()
-        cursor.close(close=True)
+        Database(database_name).connect()
         existing = True
     except Exception:
         existing = False
@@ -307,8 +336,8 @@ def restore(database_name, password, data, update=False):
     Database.restore(database_name, data)
     logger.info('RESTORE DB: %s', database_name)
     if update:
-        with Transaction().start(database_name, 0) as transaction:
-            cursor = transaction.cursor
+        with Transaction().start(database_name, 0) as transaction,\
+                transaction.connection.cursor() as cursor:
             cursor.execute(*ir_lang.select(ir_lang.code,
                     where=ir_lang.translatable))
             lang = [x[0] for x in cursor.fetchall()]
diff --git a/trytond/protocols/jsonrpc.py b/trytond/protocols/jsonrpc.py
index df9f46e..69298ef 100644
--- a/trytond/protocols/jsonrpc.py
+++ b/trytond/protocols/jsonrpc.py
@@ -1,24 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.protocols.sslsocket import SSLSocket
-from trytond.protocols.dispatcher import dispatch
-from trytond.config import config
-from trytond.protocols.common import daemon, RegisterHandlerMixin
-from trytond.exceptions import UserError, UserWarning, NotLogged, \
-    ConcurrencyException
-import SimpleXMLRPCServer
-import SimpleHTTPServer
-import SocketServer
 import traceback
-import socket
 import sys
-import os
-try:
-    import fcntl
-except ImportError:
-    fcntl = None
-import posixpath
-import urllib
 import datetime
 from decimal import Decimal
 try:
@@ -26,11 +9,13 @@ try:
 except ImportError:
     import json
 import base64
-import encodings
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
+
+from werkzeug.wrappers import Response
+from werkzeug.utils import cached_property
+from werkzeug.exceptions import BadRequest
+
+from trytond.protocols.wrappers import Request
+from trytond.exceptions import TrytonException
 
 
 class JSONDecoder(object):
@@ -61,7 +46,7 @@ JSONDecoder.register('timedelta',
 
 def _bytes_decoder(dct):
     cast = bytearray if bytes == str else bytes
-    return cast(base64.decodestring(dct['base64']))
+    return cast(base64.decodestring(dct['base64'].encode('utf-8')))
 JSONDecoder.register('bytes', _bytes_decoder)
 JSONDecoder.register('Decimal', lambda dct: Decimal(dct['decimal']))
 
@@ -118,7 +103,7 @@ JSONEncoder.register(datetime.timedelta,
         })
 _bytes_encoder = lambda o: {
     '__class__': 'bytes',
-    'base64': base64.encodestring(o),
+    'base64': base64.encodestring(o).decode('utf-8'),
     }
 JSONEncoder.register(bytes, _bytes_encoder)
 JSONEncoder.register(bytearray, _bytes_encoder)
@@ -129,266 +114,50 @@ JSONEncoder.register(Decimal,
         })
 
 
-class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
-    """Mix-in class that dispatches JSON-RPC requests.
+class JSONRequest(Request):
+    parsed_content_type = 'json'
+
+    @cached_property
+    def parsed_data(self):
+        if self.parsed_content_type in self.environ.get('CONTENT_TYPE', ''):
+            try:
+                return json.loads(self.decoded_data, object_hook=JSONDecoder())
+            except Exception:
+                raise BadRequest('Unable to read JSON request')
+        else:
+            raise BadRequest('Not a JSON request')
 
-    This class is used to register JSON-RPC method handlers
-    and then to dispatch them. There should never be any
-    reason to instantiate this class directly.
-    """
+    @cached_property
+    def method(self):
+        return self.parsed_data['method']
 
-    def _marshaled_dispatch(self, data, dispatch_method=None, path=None):
-        """Dispatches an JSON-RPC method from marshalled (JSON) data.
+    @cached_property
+    def params(self):
+        return self.parsed_data['params']
 
-        JSON-RPC methods are dispatched from the marshalled (JSON) data
-        using the _dispatch method and the result is returned as
-        marshalled data. For backwards compatibility, a dispatch
-        function can be provided as an argument (see comment in
-        SimpleJSONRPCRequestHandler.do_POST) but overriding the
-        existing method through subclassing is the prefered means
-        of changing method dispatch behavior.
-        """
-        rawreq = json.loads(data, object_hook=JSONDecoder())
 
-        req_id = rawreq.get('id', 0)
-        method = rawreq['method']
-        params = rawreq.get('params', [])
+class JSONProtocol:
+    content_type = 'json'
 
-        response = {'id': req_id}
+    @classmethod
+    def request(cls, environ):
+        return JSONRequest(environ)
 
-        try:
-            # generate response
-            if dispatch_method is not None:
-                response['result'] = dispatch_method(method, params)
-            else:
-                response['result'] = self._dispatch(method, params)
-        except (UserError, UserWarning, NotLogged,
-                ConcurrencyException), exception:
-            response['error'] = exception.args
-        except Exception:
+    @classmethod
+    def response(cls, data, request):
+        if isinstance(request, JSONRequest):
+            response = {'id': request.parsed_data.get('id', 0)}
+        else:
+            response = {}
+        if isinstance(data, TrytonException):
+            response['error'] = data.args
+        elif isinstance(data, Exception):
             tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
             for path in sys.path:
                 tb_s = tb_s.replace(path, '')
             # report exception back to server
-            response['error'] = (str(sys.exc_value), tb_s)
-
-        return json.dumps(response, cls=JSONEncoder)
-
-
-class GenericJSONRPCRequestHandler:
-
-    def _dispatch(self, method, params):
-        host, port = self.client_address[:2]
-        database_name = self.path[1:]
-        if database_name.startswith('sao/'):
-            database_name = database_name[4:]
-        method_list = method.split('.')
-        object_type = method_list[0]
-        object_name = '.'.join(method_list[1:-1])
-        method = method_list[-1]
-        args = (host, port, 'JSON-RPC', database_name, params[0], params[1],
-                object_type, object_name, method) + tuple(params[2:])
-        res = dispatch(*args)
-        return res
-
-
-class SimpleJSONRPCRequestHandler(RegisterHandlerMixin,
-        GenericJSONRPCRequestHandler,
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler,
-        SimpleHTTPServer.SimpleHTTPRequestHandler):
-    """Simple JSON-RPC request handler class.
-
-    Handles all HTTP POST requests and attempts to decode them as
-    JSON-RPC requests.
-    """
-    protocol_version = "HTTP/1.1"
-    rpc_paths = None
-    encode_threshold = 1400  # common MTU
-
-    def send_header(self, keyword, value):
-        if keyword == 'Content-type' and value == 'text/xml':
-            value = 'application/json-rpc'
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.send_header(self,
-            keyword, value)
-
-    def do_GET(self):
-        if self.is_tryton_url(self.path):
-            self.send_tryton_url(self.path)
-            return
-        SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
-
-    def do_HEAD(self):
-        if self.is_tryton_url(self.path):
-            self.send_tryton_url(self.path)
-            return
-        SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
-
-    def translate_path(self, path):
-        """Translate a /-separated PATH to the local filename syntax.
-
-        Components that mean special things to the local file system
-        (e.g. drive or directory names) are ignored.  (XXX They should
-        probably be diagnosed.)
-
-        """
-        # abandon query parameters
-        path = path.split('?', 1)[0]
-        path = path.split('#', 1)[0]
-        path = posixpath.normpath(urllib.unquote(path))
-        words = path.split('/')
-        words = filter(None, words)
-        path = config.get('jsonrpc', 'data')
-        for word in words:
-            drive, word = os.path.splitdrive(word)
-            head, word = os.path.split(word)
-            if word in (os.curdir, os.pardir):
-                continue
-            path = os.path.join(path, word)
-        return path
-
-    def is_tryton_url(self, path):
-        words = path.split('/')
-        try:
-            return words[2] in ('model', 'wizard', 'report')
-        except IndexError:
-            return False
-
-    def send_tryton_url(self, path):
-        self.send_response(300)
-        hostname = (config.get('jsonrpc', 'hostname')
-            or unicode(socket.getfqdn(), 'utf8'))
-        hostname = '.'.join(encodings.idna.ToASCII(part) for part in
-            hostname.split('.'))
-        values = {
-            'hostname': hostname,
-            'path': path,
-            }
-        content = StringIO()
-        content.write('<html')
-        content.write('<head>')
-        content.write('<meta http-equiv="Refresh" '
-            'content="0;url=tryton://%(hostname)s%(path)s"/>' % values)
-        content.write('<title>Moved</title>')
-        content.write('</head>')
-        content.write('<body>')
-        content.write('<h1>Moved</h1>')
-        content.write('<p>This page has moved to '
-            '<a href="tryton://%(hostname)s%(path)s">'
-            'tryton://%(hostname)s%(path)s</a>.</p>' % values)
-        content.write('</body>')
-        content.write('</html>')
-        length = content.tell()
-        content.seek(0)
-        self.send_header('Location', 'tryton://%(hostname)s%(path)s' % values)
-        self.send_header('Content-type', 'text/html')
-        self.send_header('Content-Length', str(length))
-        self.end_headers()
-        self.copyfile(content, self.wfile)
-        content.close()
-
-SimpleJSONRPCRequestHandler.extensions_map.update({
-        '.svg': 'image/svg+xml',
-        })
-
-
-class SecureJSONRPCRequestHandler(SimpleJSONRPCRequestHandler):
-
-    def setup(self):
-        self.request = SSLSocket(self.request)
-        SimpleJSONRPCRequestHandler.setup(self)
-
-
-class SimpleJSONRPCServer(SocketServer.TCPServer,
-        SimpleJSONRPCDispatcher):
-    """Simple JSON-RPC server.
-
-    Simple JSON-RPC server that allows functions and a single instance
-    to be installed to handle requests. The default implementation
-    attempts to dispatch JSON-RPC calls to the functions or instance
-    installed in the server. Override the _dispatch method inhereted
-    from SimpleJSONRPCDispatcher to change this behavior.
-    """
-
-    allow_reuse_address = True
-
-    # Warning: this is for debugging purposes only! Never set this to True in
-    # production code, as will be sending out sensitive information (exception
-    # and stack trace details) when exceptions are raised inside
-    # SimpleJSONRPCRequestHandler.do_POST
-    _send_traceback_header = False
-
-    def __init__(self, addr, requestHandler=SimpleJSONRPCRequestHandler,
-            logRequests=True, allow_none=False, encoding=None,
-            bind_and_activate=True):
-        self.handlers = set()
-        self.logRequests = logRequests
-
-        SimpleJSONRPCDispatcher.__init__(self, allow_none, encoding)
-        try:
-            SocketServer.TCPServer.__init__(self, addr, requestHandler,
-                    bind_and_activate)
-        except TypeError:
-            SocketServer.TCPServer.__init__(self, addr, requestHandler)
-
-        # [Bug #1222790] If possible, set close-on-exec flag; if a
-        # method spawns a subprocess, the subprocess shouldn't have
-        # the listening socket open.
-        if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
-            flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
-            flags |= fcntl.FD_CLOEXEC
-            fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
-
-    def server_close(self):
-        SocketServer.TCPServer.server_close(self)
-        for handler in self.handlers.copy():
-            self.shutdown_request(handler.request)
-
-
-class SimpleThreadedJSONRPCServer(SocketServer.ThreadingMixIn,
-        SimpleJSONRPCServer):
-    timeout = 1
-    daemon_threads = True
-    disable_nagle_algorithm = True
-
-    def server_bind(self):
-        self.socket.setsockopt(socket.SOL_SOCKET,
-                socket.SO_REUSEADDR, 1)
-        self.socket.setsockopt(socket.SOL_SOCKET,
-            socket.SO_KEEPALIVE, 1)
-        SimpleJSONRPCServer.server_bind(self)
-
-
-class SimpleThreadedJSONRPCServer6(SimpleThreadedJSONRPCServer):
-    address_family = socket.AF_INET6
-
-
-class SecureThreadedJSONRPCServer(SimpleThreadedJSONRPCServer):
-
-    def __init__(self, server_address, HandlerClass, logRequests=1):
-        SimpleThreadedJSONRPCServer.__init__(self, server_address,
-            HandlerClass, logRequests)
-        self.socket = socket.socket(self.address_family,
-            self.socket_type)
-        self.server_bind()
-        self.server_activate()
-
-
-class SecureThreadedJSONRPCServer6(SecureThreadedJSONRPCServer):
-    address_family = socket.AF_INET6
-
-
-class JSONRPCDaemon(daemon):
-
-    def __init__(self, interface, port, secure=False):
-        daemon.__init__(self, interface, port, secure, name='JSONRPCDaemon')
-        if self.secure:
-            handler_class = SecureJSONRPCRequestHandler
-            server_class = SecureThreadedJSONRPCServer
-            if self.ipv6:
-                server_class = SecureThreadedJSONRPCServer6
+            response['error'] = (str(data), tb_s)
         else:
-            handler_class = SimpleJSONRPCRequestHandler
-            server_class = SimpleThreadedJSONRPCServer
-            if self.ipv6:
-                server_class = SimpleThreadedJSONRPCServer6
-        self.server = server_class((interface, port), handler_class, 0)
+            response['result'] = data
+        return Response(json.dumps(response, cls=JSONEncoder),
+            content_type='application/json')
diff --git a/trytond/protocols/sslsocket.py b/trytond/protocols/sslsocket.py
deleted file mode 100644
index 4d12720..0000000
--- a/trytond/protocols/sslsocket.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-from trytond.config import config
-
-
-def SSLSocket(socket):
-    # Let the import error raise only when used
-    import ssl
-    return ssl.wrap_socket(socket,
-        server_side=True,
-        certfile=config.get('ssl', 'certificate'),
-        keyfile=config.get('ssl', 'privatekey'),
-        ssl_version=ssl.PROTOCOL_SSLv23)
diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py
deleted file mode 100644
index 77d2822..0000000
--- a/trytond/protocols/webdav.py
+++ /dev/null
@@ -1,594 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import SocketServer
-import socket
-import BaseHTTPServer
-import urlparse
-import time
-import urllib
-import logging
-from threading import local
-import xml.dom.minidom
-import base64
-from pywebdav.lib import WebDAVServer, iface
-from pywebdav.lib.errors import DAV_Error, DAV_NotFound, DAV_Secret, \
-    DAV_Forbidden, DAV_Requested_Range_Not_Satisfiable
-from pywebdav.lib.constants import COLLECTION, DAV_VERSION_1, DAV_VERSION_2
-from pywebdav.lib.utils import get_urifilename, quote_uri
-from pywebdav.lib.davcmd import copyone, copytree, moveone, movetree, \
-    delone, deltree
-from trytond.protocols.sslsocket import SSLSocket
-from trytond.protocols.common import daemon
-from trytond.security import login
-from trytond import __version__
-from trytond.tools.misc import LocalDict
-from trytond import backend
-from trytond.pool import Pool
-from trytond.transaction import Transaction
-from trytond.cache import Cache
-from trytond.exceptions import UserError, UserWarning, NotLogged, \
-    ConcurrencyException
-domimpl = xml.dom.minidom.getDOMImplementation()
-
-DAV_VERSION_1['version'] += ',access-control'
-DAV_VERSION_2['version'] += ',access-control'
-
-logger = logging.getLogger(__name__)
-
-
-# Local int for multi-thread
-class LocalInt(local):
-
-    def __init__(self, value=0):
-        super(LocalInt, self).__init__()
-        self.value = value
-
-    def __int__(self):
-        return int(self.value)
-
-CACHE = LocalDict()
-
-
-def setupConfig():
-
-    class ConfigDAV:
-        lockemulation = False
-        verbose = False
-        baseurl = ''
-
-        def getboolean(self, name):
-            return bool(self.get(name))
-
-        def get(self, name, default=None):
-            return getattr(self, name, default)
-
-    class Config:
-        DAV = ConfigDAV()
-
-    return Config()
-
-
-class BaseThreadedHTTPServer(SocketServer.ThreadingMixIn,
-        BaseHTTPServer.HTTPServer):
-    timeout = 1
-
-    def server_bind(self):
-        self.socket.setsockopt(socket.SOL_SOCKET,
-                socket.SO_REUSEADDR, 1)
-        self.socket.setsockopt(socket.SOL_SOCKET,
-            socket.SO_KEEPALIVE, 1)
-        BaseHTTPServer.HTTPServer.server_bind(self)
-
-
-class SecureThreadedHTTPServer(BaseThreadedHTTPServer):
-
-    def __init__(self, server_address, HandlerClass):
-        BaseThreadedHTTPServer.__init__(self, server_address, HandlerClass)
-        self.socket = socket.socket(self.address_family, self.socket_type)
-        self.server_bind()
-        self.server_activate()
-
-
-class WebDAVServerThread(daemon):
-
-    def __init__(self, interface, port, secure=False):
-        daemon.__init__(self, interface, port, secure,
-                name='WebDAVServerThread')
-        if self.secure:
-            handler_class = SecureWebDAVAuthRequestHandler
-            server_class = SecureThreadedHTTPServer
-            if self.ipv6:
-                server_class = SecureThreadedHTTPServer6
-        else:
-            handler_class = WebDAVAuthRequestHandler
-            server_class = BaseThreadedHTTPServer
-            if self.ipv6:
-                server_class = BaseThreadedHTTPServer6
-        handler_class._config = setupConfig()
-        handler_class.IFACE_CLASS = TrytonDAVInterface(interface, port, secure)
-        handler_class.IFACE_CLASS.baseurl = handler_class._config.DAV.baseurl
-        self.server = server_class((interface, port), handler_class)
-
-
-class BaseThreadedHTTPServer6(BaseThreadedHTTPServer):
-    address_family = socket.AF_INET6
-
-
-class SecureThreadedHTTPServer6(SecureThreadedHTTPServer):
-    address_family = socket.AF_INET6
-
-
-class TrytonDAVInterface(iface.dav_interface):
-
-    def __init__(self, interface, port, secure=False):
-        if secure:
-            protocol = 'https'
-        else:
-            protocol = 'http'
-        self.baseuri = '%s://%s:%s/' % (protocol, interface or
-                socket.gethostname(), port)
-        self.verbose = False
-
-    def _log_exception(self, exception):
-        if isinstance(exception, (NotLogged, ConcurrencyException, UserError,
-                    UserWarning, DAV_Error, DAV_NotFound, DAV_Secret,
-                    DAV_Forbidden)):
-            logger.debug('Exception %s', exception, exc_info=True)
-        else:
-            logger.error('Exception %s', exception, exc_info=True)
-
-    @staticmethod
-    def get_dburi(uri):
-        uri = urlparse.urlsplit(uri)[2]
-        if uri and uri[0] == '/':
-            uri = uri[1:]
-        dbname, uri = (uri.split('/', 1) + [None])[0:2]
-        if dbname:
-            dbname = urllib.unquote_plus(dbname)
-        if uri:
-            uri = urllib.unquote_plus(uri)
-        return dbname, uri
-
-    def _get_dburi(self, uri):
-        return TrytonDAVInterface.get_dburi(uri)
-
-    def get_childs(self, uri, filter=None):
-        res = []
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname:
-            database = backend.get('Database')().connect()
-            cursor = database.cursor()
-            try:
-                lists = database.list(cursor)
-            except Exception:
-                lists = []
-            finally:
-                cursor.close()
-            for dbname in lists:
-                res.append(urlparse.urljoin(uri, dbname))
-            return res
-        pool = Pool(Transaction().cursor.database_name)
-        try:
-            Collection = pool.get('webdav.collection')
-            scheme, netloc, path, params, query, fragment = \
-                urlparse.urlparse(uri)
-            if path[-1:] != '/':
-                path += '/'
-            for child in Collection.get_childs(dburi, filter=filter,
-                    cache=CACHE):
-                res.append(urlparse.urlunparse((scheme, netloc,
-                            path + child.encode('utf-8'), params, query,
-                            fragment)))
-        except KeyError:
-            return res
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def get_data(self, uri, range=None):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or (self.exists(uri) and self.is_collection(uri)):
-            res = ('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 '
-                'Transitional//EN">')
-            res += '<html>'
-            res += '<head>'
-            res += ('<meta http-equiv="Content-Type" content="text/html; '
-                'charset=utf-8">')
-            res += '<title>Tryton - WebDAV - %s</title>' % dbname or 'root'
-            res += '</head>'
-            res += '<body>'
-            res += '<h2>Collection: %s</h2>' % (get_urifilename(uri) or '/')
-            res += '<ul>'
-            if dbname:
-                scheme, netloc, path, params, query, fragment = \
-                    urlparse.urlparse(uri)
-                if path[-1:] != '/':
-                    path += '/'
-                res += ('<li><a href="%s">..</a></li>'
-                    % urlparse.urlunparse((scheme, netloc, path + '..',
-                            params, query, fragment)))
-            childs = self.get_childs(uri)
-            childs.sort()
-            for child in childs:
-                res += ('<li><a href="%s">%s</a></li>'
-                    % (quote_uri(child), get_urifilename(child)))
-            res += '</ul>'
-            res += '<hr noshade>'
-            res += ('<em>Powered by <a href="http://www.tryton.org/">'
-                'Tryton</a> version %s</em>' % __version__)
-            res += '</body>'
-            res += '</html>'
-            return res
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_data(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        if range is None:
-            return res
-        size = len(res)
-        if range[1] == '':
-            range[1] = size
-        else:
-            range[1] = int(range[1])
-        if range[1] > size:
-            range[1] = size
-        if range[0] == '':
-            range[0] = size - range[1]
-        else:
-            range[0] = int(range[0])
-        if range[0] > size:
-            raise DAV_Requested_Range_Not_Satisfiable
-        return res[range[0]:range[1]]
-
-    def put(self, uri, data, content_type=''):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            raise DAV_Forbidden
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.put(dburi, data, content_type, cache=CACHE)
-            Transaction().cursor.commit()
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            raise DAV_Error(500)
-        if res:
-            uparts = list(urlparse.urlsplit(uri))
-            uparts[2] = res
-            res = urlparse.urlunsplit(uparts)
-        return res
-
-    def mkcol(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            raise DAV_Forbidden
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.mkcol(dburi, cache=CACHE)
-            Transaction().cursor.commit()
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            raise DAV_Error(500)
-        return res
-
-    def _get_dav_resourcetype(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return COLLECTION
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_resourcetype(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def _get_dav_displayname(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return uri.split('/')[-1]
-        pool = Pool(Transaction().cursor.database_name)
-        try:
-            Collection = pool.get('webdav.collection')
-            res = Collection.get_displayname(dburi, cache=CACHE)
-        except KeyError:
-            raise DAV_NotFound
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def _get_dav_getcontentlength(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return '0'
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_contentlength(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def _get_dav_getcontenttype(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or self.is_collection(uri):
-            return "text/html"
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_contenttype(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def _get_dav_getetag(self, uri):
-        return '"' + str(self.get_lastmodified(uri)) + '"'
-
-    def get_creationdate(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return time.time()
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_creationdate(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def get_lastmodified(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return time.time()
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.get_lastmodified(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def rmcol(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return 403
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.rmcol(dburi, cache=CACHE)
-            Transaction().cursor.commit()
-        except Exception, exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            return 500
-        return res
-
-    def rm(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return 403
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.rm(dburi, cache=CACHE)
-            Transaction().cursor.commit()
-        except Exception, exception:
-            self._log_exception(exception)
-            Transaction().cursor.rollback()
-            return 500
-        return res
-
-    def exists(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        if not dbname or not dburi:
-            return 1
-        pool = Pool(Transaction().cursor.database_name)
-        Collection = pool.get('webdav.collection')
-        try:
-            res = Collection.exists(dburi, cache=CACHE)
-        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
-            self._log_exception(exception)
-            raise
-        except Exception, exception:
-            self._log_exception(exception)
-            raise DAV_Error(500)
-        return res
-
-    def is_collection(self, uri):
-        if self._get_dav_resourcetype(uri) == COLLECTION:
-            return 1
-        return 0
-
-    def copyone(self, src, dst, overwrite):
-        return copyone(self, src, dst, overwrite)
-
-    def copytree(self, src, dst, overwrite):
-        return copytree(self, src, dst, overwrite)
-
-    def moveone(self, src, dst, overwrite):
-        return moveone(self, src, dst, overwrite)
-
-    def movetree(self, src, dst, overwrite):
-        return movetree(self, src, dst, overwrite)
-
-    def delone(self, uri):
-        return delone(self, uri)
-
-    def deltree(self, uri):
-        return deltree(self, uri)
-
-    def copy(self, src, dst):
-        content = self._get_dav_getcontenttype(src)
-        data = self.get_data(src)
-        self.put(dst, data, content)
-        return 201
-
-    def copycol(self, src, dst):
-        return self.mkcol(dst)
-
-    def _get_dav_current_user_privilege_set(self, uri):
-        dbname, dburi = self._get_dburi(uri)
-        privileges = []
-        if not dbname or not dburi:
-            privileges = ['create', 'read', 'write', 'delete']
-        else:
-            pool = Pool(Transaction().cursor.database_name)
-            try:
-                Collection = pool.get('webdav.collection')
-                privileges = Collection.current_user_privilege_set(dburi,
-                        cache=CACHE)
-            except KeyError:
-                pass
-            except Exception, exception:
-                self._log_exception(exception)
-                pass
-        doc = domimpl.createDocument(None, 'privilege', None)
-        privilege = doc.documentElement
-        privilege.tagName = 'D:privilege'
-        if 'create' in privileges:
-            bind = doc.createElement('D:bind')
-            privilege.appendChild(bind)
-        if 'read' in privileges:
-            read = doc.createElement('D:read')
-            privilege.appendChild(read)
-            read_acl = doc.createElement('D:read-acl')
-            privilege.appendChild(read_acl)
-        if 'write' in privileges:
-            write = doc.createElement('D:write')
-            privilege.appendChild(write)
-            write_content = doc.createElement('D:write-content')
-            privilege.appendChild(write_content)
-            write_properties = doc.createElement('D:write-properties')
-            privilege.appendChild(write_properties)
-        if 'delete' in privileges:
-            unbind = doc.createElement('D:unbind')
-            privilege.appendChild(unbind)
-        return privilege
-
-TrytonDAVInterface.PROPS['DAV:'] = tuple(list(TrytonDAVInterface.PROPS['DAV:']
-    ) + ['current-user-privilege-set'])
-
-
-class WebDAVAuthRequestHandler(WebDAVServer.DAVRequestHandler):
-
-    def finish(self):
-        WebDAVServer.DAVRequestHandler.finish(self)
-
-        global CACHE
-        CACHE = LocalDict()
-        if not Transaction().cursor:
-            return
-        dbname = Transaction().cursor.database_name
-        Transaction().stop()
-        if dbname:
-            with Transaction().start(dbname, 0):
-                Cache.resets(dbname)
-
-    def parse_request(self):
-        if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self):
-            return False
-
-        authorization = self.headers.get('Authorization', '')
-        if authorization:
-            scheme, credentials = authorization.split()
-            if scheme != 'Basic':
-                self.send_error(501)
-                return False
-            credentials = base64.decodestring(credentials)
-            user, password = credentials.split(':', 2)
-            if not self.get_userinfo(user, password, self.command):
-                self.send_autherror(401, "Authorization Required")
-                return False
-        else:
-            if not self.get_userinfo(None, None, self.command):
-                self.send_autherror(401, "Authorization Required")
-                return False
-        return True
-
-    def get_userinfo(self, user, password, command=''):
-        path = urlparse.urlparse(self.path).path
-        dbname = urllib.unquote_plus(path.split('/', 2)[1])
-        database = backend.get('Database')().connect()
-        cursor = database.cursor()
-        databases = database.list(cursor)
-        cursor.close()
-        if not dbname or dbname not in databases:
-            return True
-        if user:
-            user = int(login(dbname, user, password, cache=False))
-            if not user:
-                return None
-        else:
-            url = urlparse.urlparse(self.path)
-            query = urlparse.parse_qs(url.query)
-            path = url.path[len(dbname) + 2:]
-            if 'key' in query:
-                key, = query['key']
-                with Transaction().start(dbname, 0) as transaction:
-                    database_list = Pool.database_list()
-                    pool = Pool(dbname)
-                    if dbname not in database_list:
-                        pool.init()
-                    Share = pool.get('webdav.share')
-                    user = Share.get_login(key, command, path)
-                    transaction.cursor.commit()
-            if not user:
-                return None
-
-        Transaction().start(dbname, user, context={
-                '_check_access': True,
-                }, autocommit=True)
-        Cache.clean(dbname)
-        return user
-
-
-class SecureWebDAVAuthRequestHandler(WebDAVAuthRequestHandler):
-
-    def setup(self):
-        self.request = SSLSocket(self.request)
-        WebDAVAuthRequestHandler.setup(self)
diff --git a/trytond/protocols/wrappers.py b/trytond/protocols/wrappers.py
new file mode 100644
index 0000000..bf53950
--- /dev/null
+++ b/trytond/protocols/wrappers.py
@@ -0,0 +1,87 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import base64
+import gzip
+from io import BytesIO
+
+from werkzeug.wrappers import Request as _Request
+from werkzeug.utils import cached_property
+from werkzeug.http import wsgi_to_bytes, bytes_to_wsgi
+from werkzeug.datastructures import Authorization
+from werkzeug.exceptions import abort
+
+from trytond import security
+
+
+class Request(_Request):
+
+    view_args = None
+
+    @property
+    def decoded_data(self):
+        if self.content_encoding == 'gzip':
+            zipfile = gzip.GzipFile(fileobj=BytesIO(self.data), mode='rb')
+            return zipfile.read()
+        else:
+            return self.data
+
+    @property
+    def parsed_data(self):
+        return self.data
+
+    @property
+    def method(self):
+        return
+
+    @property
+    def params(self):
+        return
+
+    @cached_property
+    def authorization(self):
+        authorization = super(Request, self).authorization
+        if authorization is None:
+            header = self.environ.get('HTTP_AUTHORIZATION')
+            return parse_authorization_header(header)
+        return authorization
+
+    @cached_property
+    def user_id(self):
+        database_name = self.view_args['database_name']
+        auth = self.authorization
+        if not auth:
+            abort(401)
+        if auth.type == 'session':
+            user_id = security.check(
+                database_name, auth.get('userid'), auth.get('session'))
+            if not user_id:
+                abort(403)
+        else:
+            user_id = security.login(
+                database_name, auth.username, auth.password, cache=False)
+            if not user_id:
+                abort(401)
+        return user_id
+
+
+def parse_authorization_header(value):
+    if not value:
+        return
+    value = wsgi_to_bytes(value)
+    try:
+        auth_type, auth_info = value.split(None, 1)
+        auth_type = auth_type.lower()
+    except ValueError:
+        return
+    if auth_type == b'session':
+        try:
+            username, userid, session = base64.b64decode(auth_info).split(
+                b':', 3)
+            userid = int(userid)
+        except Exception:
+            return
+        return Authorization('session', {
+                'username': bytes_to_wsgi(username),
+                'userid': userid,
+                'session': bytes_to_wsgi(session),
+                })
diff --git a/trytond/protocols/xmlrpc.py b/trytond/protocols/xmlrpc.py
index 9febacf..502f226 100644
--- a/trytond/protocols/xmlrpc.py
+++ b/trytond/protocols/xmlrpc.py
@@ -1,23 +1,19 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.protocols.sslsocket import SSLSocket
-from trytond.protocols.dispatcher import dispatch
-from trytond.protocols.common import daemon, RegisterHandlerMixin
-from trytond.exceptions import UserError, UserWarning, NotLogged, \
-    ConcurrencyException
-from trytond import security
-import SimpleXMLRPCServer
-import SocketServer
-import xmlrpclib
-import socket
-import base64
+import xmlrpclib as client
 import datetime
-from types import DictType
 import logging
 
 # convert decimal to float before marshalling:
 from decimal import Decimal
 
+from werkzeug.wrappers import Response
+from werkzeug.utils import cached_property
+from werkzeug.exceptions import BadRequest
+
+from trytond.protocols.wrappers import Request
+from trytond.exceptions import TrytonException
+
 logger = logging.getLogger(__name__)
 
 
@@ -30,7 +26,7 @@ def dump_decimal(self, value, write):
 
 def dump_bytes(self, value, write):
     self.write = write
-    value = xmlrpclib.Binary(value)
+    value = client.Binary(value)
     value.encode(self)
     del self.write
 
@@ -60,18 +56,17 @@ def dump_timedelta(self, value, write):
         }
     self.dump_struct(value, write)
 
-xmlrpclib.Marshaller.dispatch[Decimal] = dump_decimal
-xmlrpclib.Marshaller.dispatch[type(None)] = \
+client.Marshaller.dispatch[Decimal] = dump_decimal
+client.Marshaller.dispatch[type(None)] = \
         lambda self, value, write: write("<value><nil/></value>")
-xmlrpclib.Marshaller.dispatch[datetime.date] = dump_date
-xmlrpclib.Marshaller.dispatch[datetime.time] = dump_time
-xmlrpclib.Marshaller.dispatch[datetime.timedelta] = dump_timedelta
-if bytes != str:
-    xmlrpclib.Marshaller.dispatch[bytes] = dump_bytes
-xmlrpclib.Marshaller.dispatch[bytearray] = dump_bytes
+client.Marshaller.dispatch[datetime.date] = dump_date
+client.Marshaller.dispatch[datetime.time] = dump_time
+client.Marshaller.dispatch[datetime.timedelta] = dump_timedelta
+if bytes == str:
+    client.Marshaller.dispatch[bytearray] = dump_bytes
 
 
-def dump_struct(self, value, write, escape=xmlrpclib.escape):
+def dump_struct(self, value, write, escape=client.escape):
     converted_value = {}
     for k, v in value.items():
         if type(k) in (int, long):
@@ -81,7 +76,7 @@ def dump_struct(self, value, write, escape=xmlrpclib.escape):
         converted_value[k] = v
     return self.dump_struct(converted_value, write, escape=escape)
 
-xmlrpclib.Marshaller.dispatch[DictType] = dump_struct
+client.Marshaller.dispatch[dict] = dump_struct
 
 
 class XMLRPCDecoder(object):
@@ -114,159 +109,70 @@ def end_struct(self, data):
     dct = {}
     items = self._stack[mark:]
     for i in range(0, len(items), 2):
-        dct[xmlrpclib._stringify(items[i])] = items[i + 1]
+        dct[items[i]] = items[i + 1]
     dct = XMLRPCDecoder()(dct)
     self._stack[mark:] = [dct]
     self._value = 0
 
-xmlrpclib.Unmarshaller.dispatch['struct'] = end_struct
+client.Unmarshaller.dispatch['struct'] = end_struct
 
 
 def _end_dateTime(self, data):
-    value = xmlrpclib.DateTime()
+    value = client.DateTime()
     value.decode(data)
-    value = xmlrpclib._datetime_type(data)
+    value = client._datetime_type(data)
     self.append(value)
-xmlrpclib.Unmarshaller.dispatch["dateTime.iso8601"] = _end_dateTime
+client.Unmarshaller.dispatch["dateTime.iso8601"] = _end_dateTime
 
 
 def _end_base64(self, data):
-    value = xmlrpclib.Binary()
-    value.decode(data)
+    value = client.Binary()
+    value.decode(data.encode('ascii'))
     cast = bytearray if bytes == str else bytes
     self.append(cast(value.data))
     self._value = 0
-xmlrpclib.Unmarshaller.dispatch['base64'] = _end_base64
+if bytes == str:
+    client.Unmarshaller.dispatch['base64'] = _end_base64
 
 
-class GenericXMLRPCRequestHandler:
+class XMLRequest(Request):
+    parsed_content_type = 'xml'
 
-    def _dispatch(self, method, params):
-        host, port = self.client_address[:2]
-        database_name = self.path[1:]
-        user = self.tryton['user']
-        session = self.tryton['session']
-        exception_message = 'Exception calling %s%s' % (method, params)
-        try:
+    @cached_property
+    def parsed_data(self):
+        if self.parsed_content_type in self.environ.get('CONTENT_TYPE', ''):
             try:
-                method_list = method.split('.')
-                object_type = method_list[0]
-                object_name = '.'.join(method_list[1:-1])
-                method = method_list[-1]
-                if object_type == 'system' and method == 'getCapabilities':
-                    return {
-                        'introspect': {
-                            'specUrl': ('http://xmlrpc-c.sourceforge.net/'
-                                'xmlrpc-c/introspection.html'),
-                            'specVersion': 1,
-                        },
-                    }
-                return dispatch(host, port, 'XML-RPC', database_name, user,
-                        session, object_type, object_name, method, *params)
-            except (NotLogged, ConcurrencyException), exception:
-                logger.debug(exception_message, exc_info=True)
-                raise xmlrpclib.Fault(exception.code, str(exception))
-            except (UserError, UserWarning), exception:
-                logger.debug(exception_message, exc_info=True)
-                error, description = exception.args
-                raise xmlrpclib.Fault(exception.code, str(exception))
-            except Exception, exception:
-                logger.error(exception_message, exc_info=True)
-                raise xmlrpclib.Fault(255, str(exception))
-        finally:
-            security.logout(database_name, user, session)
-
-
-class SimpleXMLRPCRequestHandler(RegisterHandlerMixin,
-        GenericXMLRPCRequestHandler,
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
-    protocol_version = "HTTP/1.1"
-    rpc_paths = None
-    encode_threshold = 1400  # common MTU
-
-    def parse_request(self):
-        res = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.parse_request(self)
-        if not res:
-            return res
-        database_name = self.path[1:]
-        if not database_name:
-            self.tryton = {'user': None, 'session': None}
-            return res
-        try:
-            method, up64 = self.headers['Authorization'].split(None, 1)
-            if method.strip().lower() == 'basic':
-                user, password = base64.decodestring(up64).split(':', 1)
-                user_id, session = security.login(database_name, user,
-                        password)
-                self.tryton = {'user': user_id, 'session': session}
-                return res
-        except Exception:
-            pass
-        self.send_error(401, 'Unauthorized')
-        self.send_header("WWW-Authenticate", 'Basic realm="Tryton"')
-        return False
-
-
-class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
-
-    def setup(self):
-        self.request = SSLSocket(self.request)
-        SimpleXMLRPCRequestHandler.setup(self)
-
-
-class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
-        SimpleXMLRPCServer.SimpleXMLRPCServer):
-    timeout = 1
-    daemon_threads = True
-
-    def __init__(self, server_address, HandlerClass, logRequests=1):
-        self.handlers = set()
-        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, server_address,
-            HandlerClass, logRequests)
-
-    def server_bind(self):
-        self.socket.setsockopt(socket.SOL_SOCKET,
-                socket.SO_REUSEADDR, 1)
-        self.socket.setsockopt(socket.SOL_SOCKET,
-            socket.SO_KEEPALIVE, 1)
-        SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
-
-    def server_close(self):
-        SimpleXMLRPCServer.SimpleXMLRPCServer.server_close(self)
-        for handler in self.handlers.copy():
-            self.shutdown_request(handler.request)
-
-
-class SimpleThreadedXMLRPCServer6(SimpleThreadedXMLRPCServer):
-    address_family = socket.AF_INET6
-
-
-class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer):
-
-    def __init__(self, server_address, HandlerClass, logRequests=1):
-        SimpleThreadedXMLRPCServer.__init__(self, server_address, HandlerClass,
-                logRequests)
-        self.socket = socket.socket(self.address_family, self.socket_type)
-        self.server_bind()
-        self.server_activate()
-
-
-class SecureThreadedXMLRPCServer6(SecureThreadedXMLRPCServer):
-    address_family = socket.AF_INET6
-
-
-class XMLRPCDaemon(daemon):
-
-    def __init__(self, interface, port, secure=False):
-        daemon.__init__(self, interface, port, secure, name='XMLRPCDaemon')
-        if self.secure:
-            handler_class = SecureXMLRPCRequestHandler
-            server_class = SecureThreadedXMLRPCServer
-            if self.ipv6:
-                server_class = SecureThreadedXMLRPCServer6
+                # TODO replace by own loads
+                return client.loads(self.decoded_data)
+            except Exception:
+                raise BadRequest('Unable to read XMl request')
+        else:
+            raise BadRequest('Not an XML request')
+
+    @property
+    def method(self):
+        return self.parsed_data[1]
+
+    @property
+    def params(self):
+        return self.parsed_data[0]
+
+
+class XMLProtocol:
+    content_type = 'xml'
+
+    @classmethod
+    def request(cls, environ):
+        return XMLRequest(environ)
+
+    @classmethod
+    def response(cls, data, request):
+        if isinstance(data, TrytonException):
+            data = client.Fault(data.code, str(data))
+        elif isinstance(data, Exception):
+            data = client.Fault(255, str(data))
         else:
-            handler_class = SimpleXMLRPCRequestHandler
-            server_class = SimpleThreadedXMLRPCServer
-            if self.ipv6:
-                server_class = SimpleThreadedXMLRPCServer6
-        self.server = server_class((interface, port), handler_class, 0)
+            data = (data,)
+        return Response(client.dumps(
+                data, methodresponse=True, allow_none=True),
+            content_type='text/xml')
diff --git a/trytond/report/report.py b/trytond/report/report.py
index 078b1ea..4ace05e 100644
--- a/trytond/report/report.py
+++ b/trytond/report/report.py
@@ -25,6 +25,10 @@ MIMETYPES = {
     'odp': 'application/vnd.oasis.opendocument.presentation',
     'ods': 'application/vnd.oasis.opendocument.spreadsheet',
     'odg': 'application/vnd.oasis.opendocument.graphics',
+    'plain': 'text/plain',
+    'xml': 'text/xml',
+    'html': 'text/html',
+    'xhtml': 'text/xhtml',
     }
 FORMAT2EXT = {
     'doc6': 'doc',
@@ -70,7 +74,7 @@ class TranslateFactory:
             self.cache[self.language] = {}
             translations = self.translation.search([
                 ('lang', '=', self.language),
-                ('type', '=', 'odt'),
+                ('type', '=', 'report'),
                 ('name', '=', self.report_name),
                 ('value', '!=', ''),
                 ('value', '!=', None),
@@ -141,7 +145,8 @@ class Report(URLMixin, PoolBase):
         report_context = cls.get_context(records, data)
         oext, content = cls.convert(action_report,
             cls.render(action_report, report_context))
-        content = bytearray(content) if bytes == str else bytes(content)
+        if not isinstance(content, unicode):
+            content = bytearray(content) if bytes == str else bytes(content)
         return (oext, content, action_report.direct_print, action_report.name)
 
     @classmethod
diff --git a/trytond/res/ir.py b/trytond/res/ir.py
index ddebcab..754a622 100644
--- a/trytond/res/ir.py
+++ b/trytond/res/ir.py
@@ -2,7 +2,6 @@
 # this repository contains the full copyright notices and license terms.
 from ..model import ModelSQL, fields
 from .. import backend
-from ..transaction import Transaction
 from ..pool import Pool, PoolMeta
 
 __all__ = [
@@ -11,7 +10,6 @@ __all__ = [
     'SequenceTypeGroup', 'Sequence', 'SequenceStrict',
     'ModuleConfigWizardItem',
     ]
-__metaclass__ = PoolMeta
 
 
 class UIMenuGroup(ModelSQL):
@@ -25,13 +23,12 @@ class UIMenuGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'ir_ui_menu_group_rel', cls._table)
-        TableHandler.sequence_rename(cursor, 'ir_ui_menu_group_rel_id_seq',
+        TableHandler.table_rename('ir_ui_menu_group_rel', cls._table)
+        TableHandler.sequence_rename('ir_ui_menu_group_rel_id_seq',
             cls._table + '_id_seq')
         # Migration from 2.0 menu_id and gid renamed into menu group
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('menu_id', 'menu')
         table.column_rename('gid', 'group')
         super(UIMenuGroup, cls).__register__(module_name)
@@ -67,13 +64,12 @@ class ActionGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'ir_action_group_rel', cls._table)
-        TableHandler.sequence_rename(cursor, 'ir_action_group_rel_id_seq',
+        TableHandler.table_rename('ir_action_group_rel', cls._table)
+        TableHandler.sequence_rename('ir_action_group_rel_id_seq',
             cls._table + '_id_seq')
         # Migration from 2.0 action_id and gid renamed into action and group
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('action_id', 'action')
         table.column_rename('gid', 'group')
         super(ActionGroup, cls).__register__(module_name)
@@ -122,13 +118,11 @@ class ModelFieldGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'ir_model_field_group_rel',
-            cls._table)
-        TableHandler.sequence_rename(cursor, 'ir_model_field_group_rel_id_seq',
+        TableHandler.table_rename('ir_model_field_group_rel', cls._table)
+        TableHandler.sequence_rename('ir_model_field_group_rel_id_seq',
             cls._table + '_id_seq')
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         # Migration from 2.6: field_id and group_id renamed to field and group
         table.column_rename('field_id', 'field')
         table.column_rename('group_id', 'group')
@@ -182,14 +176,13 @@ class RuleGroupGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'group_rule_group_rel', cls._table)
-        TableHandler.sequence_rename(cursor, 'group_rule_group_rel_id_seq',
+        TableHandler.table_rename('group_rule_group_rel', cls._table)
+        TableHandler.sequence_rename('group_rule_group_rel_id_seq',
             cls._table + '_id_seq')
         # Migration from 2.0 rule_group_id and group_id renamed into rule_group
         # and group
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('rule_group_id', 'rule_group')
         table.column_rename('group_id', 'group')
         super(RuleGroupGroup, cls).__register__(module_name)
@@ -206,20 +199,20 @@ class RuleGroupUser(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'user_rule_group_rel', cls._table)
-        TableHandler.sequence_rename(cursor, 'user_rule_group_rel_id_seq',
+        TableHandler.table_rename('user_rule_group_rel', cls._table)
+        TableHandler.sequence_rename('user_rule_group_rel_id_seq',
             cls._table + '_id_seq')
         # Migration from 2.0 rule_group_id and user_id renamed into rule_group
         # and user
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('rule_group_id', 'rule_group')
         table.column_rename('user_id', 'user')
         super(RuleGroupUser, cls).__register__(module_name)
 
 
 class Lang:
+    __metaclass__ = PoolMeta
     __name__ = 'ir.lang'
 
     @classmethod
@@ -230,6 +223,7 @@ class Lang:
 
 
 class SequenceType:
+    __metaclass__ = PoolMeta
     __name__ = 'ir.sequence.type'
     groups = fields.Many2Many('ir.sequence.type-res.group', 'sequence_type',
             'group', 'User Groups',
@@ -268,6 +262,7 @@ class SequenceTypeGroup(ModelSQL):
 
 
 class Sequence:
+    __metaclass__ = PoolMeta
     __name__ = 'ir.sequence'
     groups = fields.Function(fields.Many2Many('res.group', None, None,
         'User Groups'), 'get_groups', searcher='search_groups')
@@ -306,6 +301,7 @@ class SequenceStrict(Sequence):
 
 
 class ModuleConfigWizardItem:
+    __metaclass__ = PoolMeta
     __name__ = 'ir.module.config_wizard.item'
 
     @classmethod
diff --git a/trytond/res/locale/es_EC.po b/trytond/res/locale/es_EC.po
index fca7257..df859ea 100644
--- a/trytond/res/locale/es_EC.po
+++ b/trytond/res/locale/es_EC.po
@@ -328,7 +328,7 @@ msgstr "Creado por usuario"
 
 msgctxt "field:res.user,email:"
 msgid "Email"
-msgstr "Correo electrónico"
+msgstr "Email"
 
 msgctxt "field:res.user,groups:"
 msgid "Groups"
diff --git a/trytond/res/locale/es_MX.po b/trytond/res/locale/es_MX.po
index 1e3328e..29c1306 100644
--- a/trytond/res/locale/es_MX.po
+++ b/trytond/res/locale/es_MX.po
@@ -640,13 +640,15 @@ msgctxt "view:res.group:"
 msgid "Access Permissions"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:res.group:"
 msgid "Group"
-msgstr ""
+msgstr "Grupo"
 
+#, fuzzy
 msgctxt "view:res.group:"
 msgid "Groups"
-msgstr ""
+msgstr "Grupos"
 
 msgctxt "view:res.group:"
 msgid "Members"
@@ -664,21 +666,24 @@ msgctxt "view:res.user.config.start:"
 msgid "You can now add some users into the system."
 msgstr ""
 
+#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warning"
-msgstr ""
+msgstr "Avisos"
 
+#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warnings"
-msgstr ""
+msgstr "Avisos"
 
 msgctxt "view:res.user:"
 msgid "Access Permissions"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:res.user:"
 msgid "Actions"
-msgstr ""
+msgstr "Acciones"
 
 msgctxt "view:res.user:"
 msgid "Group Membership"
@@ -688,13 +693,15 @@ msgctxt "view:res.user:"
 msgid "Preferences"
 msgstr ""
 
+#, fuzzy
 msgctxt "view:res.user:"
 msgid "User"
-msgstr ""
+msgstr "Usuario"
 
+#, fuzzy
 msgctxt "view:res.user:"
 msgid "Users"
-msgstr ""
+msgstr "Usuarios"
 
 msgctxt "wizard_button:res.user.config,start,end:"
 msgid "Cancel"
diff --git a/trytond/res/locale/hu_HU.po b/trytond/res/locale/hu_HU.po
index 8ee0ed4..6eaf59b 100644
--- a/trytond/res/locale/hu_HU.po
+++ b/trytond/res/locale/hu_HU.po
@@ -642,11 +642,11 @@ msgstr ""
 
 msgctxt "view:res.group:"
 msgid "Group"
-msgstr ""
+msgstr "Csoport"
 
 msgctxt "view:res.group:"
 msgid "Groups"
-msgstr ""
+msgstr "Csoportok"
 
 msgctxt "view:res.group:"
 msgid "Members"
@@ -664,13 +664,14 @@ msgctxt "view:res.user.config.start:"
 msgid "You can now add some users into the system."
 msgstr ""
 
+#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warning"
-msgstr ""
+msgstr "Figyelmeztetések"
 
 msgctxt "view:res.user.warning:"
 msgid "Warnings"
-msgstr ""
+msgstr "Figyelmeztetések"
 
 msgctxt "view:res.user:"
 msgid "Access Permissions"
@@ -678,7 +679,7 @@ msgstr ""
 
 msgctxt "view:res.user:"
 msgid "Actions"
-msgstr ""
+msgstr "Műveletek"
 
 msgctxt "view:res.user:"
 msgid "Group Membership"
@@ -690,11 +691,11 @@ msgstr ""
 
 msgctxt "view:res.user:"
 msgid "User"
-msgstr ""
+msgstr "Felhasználó"
 
 msgctxt "view:res.user:"
 msgid "Users"
-msgstr ""
+msgstr "Felhasználók"
 
 msgctxt "wizard_button:res.user.config,start,end:"
 msgid "Cancel"
diff --git a/trytond/res/locale/nl_NL.po b/trytond/res/locale/lo_LA.po
similarity index 81%
copy from trytond/res/locale/nl_NL.po
copy to trytond/res/locale/lo_LA.po
index 8e5a2b2..d2cc6c0 100644
--- a/trytond/res/locale/nl_NL.po
+++ b/trytond/res/locale/lo_LA.po
@@ -20,10 +20,9 @@ msgctxt "error:res.user:"
 msgid "You can not have two users with the same login!"
 msgstr ""
 
-#, fuzzy
 msgctxt "field:ir.action-res.group,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr ""
 
 msgctxt "field:ir.action-res.group,create_date:"
 msgid "Create Date"
@@ -36,29 +35,31 @@ msgstr ""
 #, fuzzy
 msgctxt "field:ir.action-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
+#, fuzzy
 msgctxt "field:ir.action-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:ir.action-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
+#, fuzzy
 msgctxt "field:ir.action-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:ir.action-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
-#, fuzzy
 msgctxt "field:ir.model.button-res.group,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr ""
 
 msgctxt "field:ir.model.button-res.group,button:"
 msgid "Button"
@@ -75,24 +76,27 @@ msgstr ""
 #, fuzzy
 msgctxt "field:ir.model.button-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
+#, fuzzy
 msgctxt "field:ir.model.button-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:ir.model.button-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
+#, fuzzy
 msgctxt "field:ir.model.button-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:ir.model.button-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.model.field-res.group,create_date:"
 msgid "Create Date"
@@ -109,24 +113,27 @@ msgstr ""
 #, fuzzy
 msgctxt "field:ir.model.field-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
+#, fuzzy
 msgctxt "field:ir.model.field-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:ir.model.field-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
+#, fuzzy
 msgctxt "field:ir.model.field-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:ir.model.field-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.rule.group-res.group,create_date:"
 msgid "Create Date"
@@ -136,19 +143,17 @@ msgctxt "field:ir.rule.group-res.group,create_uid:"
 msgid "Create User"
 msgstr ""
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
 msgctxt "field:ir.rule.group-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 msgctxt "field:ir.rule.group-res.group,rule_group:"
 msgid "Rule Group"
@@ -156,11 +161,11 @@ msgstr ""
 
 msgctxt "field:ir.rule.group-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
 msgctxt "field:ir.rule.group-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.rule.group-res.user,create_date:"
 msgid "Create Date"
@@ -170,43 +175,43 @@ msgctxt "field:ir.rule.group-res.user,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:ir.rule.group-res.user,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.user,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 msgctxt "field:ir.rule.group-res.user,rule_group:"
 msgid "Rule Group"
 msgstr ""
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.user,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
 msgctxt "field:ir.rule.group-res.user,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
 msgctxt "field:ir.rule.group-res.user,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.sequence,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "ກຸ່ມຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.sequence.strict,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "ກຸ່ມຜູ້ໃຊ້ງານ"
 
+#, fuzzy
 msgctxt "field:ir.sequence.type,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "ກຸ່ມຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.sequence.type-res.group,create_date:"
 msgid "Create Date"
@@ -218,29 +223,28 @@ msgstr ""
 
 msgctxt "field:ir.sequence.type-res.group,group:"
 msgid "User Groups"
-msgstr ""
+msgstr "ກຸ່ມຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.sequence.type-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:ir.sequence.type-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
-#, fuzzy
 msgctxt "field:ir.sequence.type-res.group,sequence_type:"
 msgid "Sequence Type"
-msgstr "Reeks type"
+msgstr ""
 
 msgctxt "field:ir.sequence.type-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
 msgctxt "field:ir.sequence.type-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:ir.ui.menu-res.group,create_date:"
 msgid "Create Date"
@@ -253,29 +257,31 @@ msgstr ""
 #, fuzzy
 msgctxt "field:ir.ui.menu-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,menu:"
 msgid "Menu"
-msgstr "Menu"
+msgstr ""
 
 #, fuzzy
 msgctxt "field:ir.ui.menu-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:res.group,create_date:"
 msgid "Create Date"
@@ -289,9 +295,10 @@ msgctxt "field:res.group,field_access:"
 msgid "Access Field"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 msgctxt "field:res.group,menu_access:"
 msgid "Access Menu"
@@ -304,12 +311,12 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.group,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 #, fuzzy
 msgctxt "field:res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 msgctxt "field:res.group,rule_groups:"
 msgid "Rules"
@@ -318,25 +325,25 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.group,users:"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "ຜູ້ໃຊ້"
 
+#, fuzzy
 msgctxt "field:res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
-#, fuzzy
 msgctxt "field:res.user,actions:"
 msgid "Actions"
-msgstr "Acties"
+msgstr ""
 
-#, fuzzy
 msgctxt "field:res.user,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr ""
 
 msgctxt "field:res.user,create_date:"
 msgid "Create Date"
@@ -346,24 +353,23 @@ msgctxt "field:res.user,create_uid:"
 msgid "Create User"
 msgstr ""
 
-#, fuzzy
 msgctxt "field:res.user,email:"
 msgid "Email"
-msgstr "E-mail"
+msgstr ""
 
 #, fuzzy
 msgctxt "field:res.user,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "ໝວດ"
 
+#, fuzzy
 msgctxt "field:res.user,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
-#, fuzzy
 msgctxt "field:res.user,language:"
 msgid "Language"
-msgstr "Taal"
+msgstr ""
 
 msgctxt "field:res.user,language_direction:"
 msgid "Language Direction"
@@ -380,7 +386,7 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.user,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 msgctxt "field:res.user,password:"
 msgid "Password"
@@ -397,7 +403,7 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.user,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 msgctxt "field:res.user,rule_groups:"
 msgid "Rules"
@@ -419,18 +425,19 @@ msgctxt "field:res.user,warnings:"
 msgid "Warnings"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.user,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.user,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
-#, fuzzy
 msgctxt "field:res.user-ir.action,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr ""
 
 msgctxt "field:res.user-ir.action,create_date:"
 msgid "Create Date"
@@ -440,27 +447,30 @@ msgctxt "field:res.user-ir.action,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.user-ir.action,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:res.user-ir.action,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 #, fuzzy
 msgctxt "field:res.user-ir.action,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
+#, fuzzy
 msgctxt "field:res.user-ir.action,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.user-ir.action,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:res.user-res.group,create_date:"
 msgid "Create Date"
@@ -473,33 +483,37 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.user-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
+#, fuzzy
 msgctxt "field:res.user-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:res.user-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 #, fuzzy
 msgctxt "field:res.user-res.group,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
+#, fuzzy
 msgctxt "field:res.user-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.user-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
+#, fuzzy
 msgctxt "field:res.user.config.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 msgctxt "field:res.user.login.attempt,create_date:"
 msgid "Create Date"
@@ -509,9 +523,10 @@ msgctxt "field:res.user.login.attempt,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.user.login.attempt,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 msgctxt "field:res.user.login.attempt,login:"
 msgid "Login"
@@ -520,15 +535,17 @@ msgstr ""
 #, fuzzy
 msgctxt "field:res.user.login.attempt,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
+#, fuzzy
 msgctxt "field:res.user.login.attempt,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.user.login.attempt,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "field:res.user.warning,always:"
 msgid "Always"
@@ -542,32 +559,35 @@ msgctxt "field:res.user.warning,create_uid:"
 msgid "Create User"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.user.warning,id:"
 msgid "ID"
-msgstr ""
+msgstr "ເລກປະຈຳໂຕ"
 
 #, fuzzy
 msgctxt "field:res.user.warning,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 #, fuzzy
 msgctxt "field:res.user.warning,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "ຊື່"
 
 #, fuzzy
 msgctxt "field:res.user.warning,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
+#, fuzzy
 msgctxt "field:res.user.warning,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "ຂຽນວັນທີ"
 
+#, fuzzy
 msgctxt "field:res.user.warning,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "ຂຽນຜູ້ໃຊ້ງານ"
 
 msgctxt "help:ir.sequence.type,groups:"
 msgid "Groups allowed to edit the sequences of this type"
@@ -580,7 +600,7 @@ msgstr ""
 #, fuzzy
 msgctxt "model:ir.action,name:act_group_form"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "ໝວດ"
 
 msgctxt "model:ir.action,name:act_user_config"
 msgid "Configure Users"
@@ -589,7 +609,7 @@ msgstr ""
 #, fuzzy
 msgctxt "model:ir.action,name:act_user_form"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "ຜູ້ໃຊ້"
 
 msgctxt "model:ir.action-res.group,name:"
 msgid "Action - Group"
@@ -622,17 +642,17 @@ msgstr ""
 #, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_group_form"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "ໝວດ"
 
 #, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_res"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "ຜູ້ໃຊ້"
 
 #, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_user_form"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "ຜູ້ໃຊ້"
 
 msgctxt "model:ir.ui.menu-res.group,name:"
 msgid "UI Menu - Group"
@@ -641,21 +661,21 @@ msgstr ""
 #, fuzzy
 msgctxt "model:res.group,name:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
 #, fuzzy
 msgctxt "model:res.group,name:group_admin"
 msgid "Administration"
-msgstr "Systeembeheer"
+msgstr "ຜູ້ບໍລິຫານ"
 
 #, fuzzy
 msgctxt "model:res.user,name:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
 msgctxt "model:res.user,name:user_admin"
 msgid "Administrator"
-msgstr ""
+msgstr "ຜູ້ບໍລິຫານ"
 
 msgctxt "model:res.user,name:user_trigger"
 msgid "Cron Trigger"
@@ -665,9 +685,10 @@ msgctxt "model:res.user-ir.action,name:"
 msgid "User - Action"
 msgstr ""
 
+#, fuzzy
 msgctxt "model:res.user-res.group,name:"
 msgid "User - Group"
-msgstr ""
+msgstr "ກຸ່ມຜູ້ໃຊ້ງານ"
 
 msgctxt "model:res.user.config.start,name:"
 msgid "User Config Init"
@@ -688,12 +709,11 @@ msgstr ""
 #, fuzzy
 msgctxt "view:res.group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "ກຸ່ມ"
 
-#, fuzzy
 msgctxt "view:res.group:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "ໝວດ"
 
 msgctxt "view:res.group:"
 msgid "Members"
@@ -711,10 +731,9 @@ msgctxt "view:res.user.config.start:"
 msgid "You can now add some users into the system."
 msgstr ""
 
-#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warning"
-msgstr "Waarschuwing"
+msgstr ""
 
 msgctxt "view:res.user.warning:"
 msgid "Warnings"
@@ -724,10 +743,9 @@ msgctxt "view:res.user:"
 msgid "Access Permissions"
 msgstr ""
 
-#, fuzzy
 msgctxt "view:res.user:"
 msgid "Actions"
-msgstr "Acties"
+msgstr ""
 
 msgctxt "view:res.user:"
 msgid "Group Membership"
@@ -737,31 +755,27 @@ msgctxt "view:res.user:"
 msgid "Preferences"
 msgstr ""
 
-#, fuzzy
 msgctxt "view:res.user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "ຜູ້ໃຊ້"
 
 #, fuzzy
 msgctxt "view:res.user:"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "ຜູ້ໃຊ້"
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "ຍົກເລີກ"
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,start,user:"
 msgid "OK"
-msgstr "Oké"
+msgstr ""
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,user,add:"
 msgid "Add"
-msgstr "Toevoegen"
+msgstr ""
 
 msgctxt "wizard_button:res.user.config,user,end:"
 msgid "End"
-msgstr ""
+msgstr "ສິ້ນສຸດ"
diff --git a/trytond/res/locale/nl_NL.po b/trytond/res/locale/nl_NL.po
index 8e5a2b2..75fbc7f 100644
--- a/trytond/res/locale/nl_NL.po
+++ b/trytond/res/locale/nl_NL.po
@@ -415,9 +415,10 @@ msgctxt "field:res.user,status_bar:"
 msgid "Status Bar"
 msgstr ""
 
+#, fuzzy
 msgctxt "field:res.user,warnings:"
 msgid "Warnings"
-msgstr ""
+msgstr "Waarschuwing"
 
 msgctxt "field:res.user,write_date:"
 msgid "Write Date"
@@ -653,9 +654,10 @@ msgctxt "model:res.user,name:"
 msgid "User"
 msgstr "Gebruiker"
 
+#, fuzzy
 msgctxt "model:res.user,name:user_admin"
 msgid "Administrator"
-msgstr ""
+msgstr "Systeembeheer"
 
 msgctxt "model:res.user,name:user_trigger"
 msgid "Cron Trigger"
@@ -716,9 +718,10 @@ msgctxt "view:res.user.warning:"
 msgid "Warning"
 msgstr "Waarschuwing"
 
+#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warnings"
-msgstr ""
+msgstr "Waarschuwing"
 
 msgctxt "view:res.user:"
 msgid "Access Permissions"
diff --git a/trytond/res/locale/nl_NL.po b/trytond/res/locale/zh_CN.po
similarity index 75%
copy from trytond/res/locale/nl_NL.po
copy to trytond/res/locale/zh_CN.po
index 8e5a2b2..d3b16f8 100644
--- a/trytond/res/locale/nl_NL.po
+++ b/trytond/res/locale/zh_CN.po
@@ -4,764 +4,710 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
 
 msgctxt "error:res.group:"
 msgid "The name of the group must be unique!"
-msgstr ""
+msgstr "用户组标识必须唯一!"
 
 msgctxt "error:res.user:"
 msgid ""
 "Users can not be deleted for logging purpose.\n"
 "Instead you must inactivate them."
-msgstr ""
+msgstr "禁止用户登录请封闭帐号而非删除用户."
 
 msgctxt "error:res.user:"
 msgid "Wrong password!"
-msgstr ""
+msgstr "密码错误!"
 
 msgctxt "error:res.user:"
 msgid "You can not have two users with the same login!"
-msgstr ""
+msgstr "用户的登录名不能相同!"
 
-#, fuzzy
 msgctxt "field:ir.action-res.group,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "操作"
 
 msgctxt "field:ir.action-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.action-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.action-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.action-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.action-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.action-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.action-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
-#, fuzzy
 msgctxt "field:ir.model.button-res.group,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:ir.model.button-res.group,button:"
 msgid "Button"
-msgstr ""
+msgstr "按钮"
 
 msgctxt "field:ir.model.button-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.model.button-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.model.button-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.model.button-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.model.button-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.model.button-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.button-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.model.field-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期:"
 
 msgctxt "field:ir.model.field-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.model.field-res.group,field:"
 msgid "Model Field"
-msgstr ""
+msgstr "模型数据"
 
-#, fuzzy
 msgctxt "field:ir.model.field-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.model.field-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.model.field-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.model.field-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.model.field-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.rule.group-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.rule.group-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.rule.group-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.rule.group-res.group,rule_group:"
 msgid "Rule Group"
-msgstr ""
+msgstr "规则组"
 
 msgctxt "field:ir.rule.group-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.rule.group-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.rule.group-res.user,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.rule.group-res.user,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.rule.group-res.user,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.user,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.rule.group-res.user,rule_group:"
 msgid "Rule Group"
-msgstr ""
+msgstr "规则组"
 
-#, fuzzy
 msgctxt "field:ir.rule.group-res.user,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:ir.rule.group-res.user,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.rule.group-res.user,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.sequence,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "用户组"
 
 msgctxt "field:ir.sequence.strict,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "用户组"
 
 msgctxt "field:ir.sequence.type,groups:"
 msgid "User Groups"
-msgstr ""
+msgstr "用户组"
 
 msgctxt "field:ir.sequence.type-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.sequence.type-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:ir.sequence.type-res.group,group:"
 msgid "User Groups"
-msgstr ""
+msgstr "用户组"
 
 msgctxt "field:ir.sequence.type-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.sequence.type-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:ir.sequence.type-res.group,sequence_type:"
 msgid "Sequence Type"
-msgstr "Reeks type"
+msgstr "序列类型"
 
 msgctxt "field:ir.sequence.type-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.sequence.type-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:ir.ui.menu-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:ir.ui.menu-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:ir.ui.menu-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,menu:"
 msgid "Menu"
-msgstr "Menu"
+msgstr "菜单"
 
-#, fuzzy
 msgctxt "field:ir.ui.menu-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:ir.ui.menu-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:ir.ui.menu-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:res.group,field_access:"
 msgid "Access Field"
-msgstr ""
+msgstr "数据权限"
 
 msgctxt "field:res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:res.group,menu_access:"
 msgid "Access Menu"
-msgstr ""
+msgstr "菜单权限"
 
 msgctxt "field:res.group,model_access:"
 msgid "Access Model"
-msgstr ""
+msgstr "模型权限"
 
-#, fuzzy
 msgctxt "field:res.group,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:res.group,rule_groups:"
 msgid "Rules"
-msgstr ""
+msgstr "规则"
 
-#, fuzzy
 msgctxt "field:res.group,users:"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
 msgctxt "field:res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
-#, fuzzy
 msgctxt "field:res.user,actions:"
 msgid "Actions"
-msgstr "Acties"
+msgstr "操作"
 
-#, fuzzy
 msgctxt "field:res.user,active:"
 msgid "Active"
-msgstr "Actief"
+msgstr "启用"
 
 msgctxt "field:res.user,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.user,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:res.user,email:"
 msgid "Email"
-msgstr "E-mail"
+msgstr "电子邮件"
 
-#, fuzzy
 msgctxt "field:res.user,groups:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "field:res.user,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:res.user,language:"
 msgid "Language"
-msgstr "Taal"
+msgstr "语言"
 
 msgctxt "field:res.user,language_direction:"
 msgid "Language Direction"
-msgstr ""
+msgstr "语言方向"
 
 msgctxt "field:res.user,login:"
 msgid "Login"
-msgstr ""
+msgstr "登录"
 
 msgctxt "field:res.user,menu:"
 msgid "Menu Action"
-msgstr ""
+msgstr "菜单动作"
 
-#, fuzzy
 msgctxt "field:res.user,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:res.user,password:"
 msgid "Password"
-msgstr ""
+msgstr "密码"
 
 msgctxt "field:res.user,password_hash:"
 msgid "Password Hash"
-msgstr ""
+msgstr "密码HASH"
 
 msgctxt "field:res.user,pyson_menu:"
 msgid "PySON Menu"
-msgstr ""
+msgstr "PYSON 菜单"
 
-#, fuzzy
 msgctxt "field:res.user,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:res.user,rule_groups:"
 msgid "Rules"
-msgstr ""
+msgstr "规则"
 
 msgctxt "field:res.user,sessions:"
 msgid "Sessions"
-msgstr ""
+msgstr "进程"
 
 msgctxt "field:res.user,signature:"
 msgid "Signature"
-msgstr ""
+msgstr "印签"
 
 msgctxt "field:res.user,status_bar:"
 msgid "Status Bar"
-msgstr ""
+msgstr "状态烂"
 
 msgctxt "field:res.user,warnings:"
 msgid "Warnings"
-msgstr ""
+msgstr "警告"
 
 msgctxt "field:res.user,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.user,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
-#, fuzzy
 msgctxt "field:res.user-ir.action,action:"
 msgid "Action"
-msgstr "Actie"
+msgstr "操作"
 
 msgctxt "field:res.user-ir.action,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.user-ir.action,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:res.user-ir.action,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:res.user-ir.action,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:res.user-ir.action,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:res.user-ir.action,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.user-ir.action,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:res.user-res.group,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.user-res.group,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
-#, fuzzy
 msgctxt "field:res.user-res.group,group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
 msgctxt "field:res.user-res.group,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:res.user-res.group,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:res.user-res.group,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:res.user-res.group,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.user-res.group,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:res.user.config.start,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:res.user.login.attempt,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.user.login.attempt,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:res.user.login.attempt,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
 msgctxt "field:res.user.login.attempt,login:"
 msgid "Login"
-msgstr ""
+msgstr "登录"
 
-#, fuzzy
 msgctxt "field:res.user.login.attempt,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
 msgctxt "field:res.user.login.attempt,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.user.login.attempt,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "field:res.user.warning,always:"
 msgid "Always"
-msgstr ""
+msgstr "总是"
 
 msgctxt "field:res.user.warning,create_date:"
 msgid "Create Date"
-msgstr ""
+msgstr "创建日期"
 
 msgctxt "field:res.user.warning,create_uid:"
 msgid "Create User"
-msgstr ""
+msgstr "创建者"
 
 msgctxt "field:res.user.warning,id:"
 msgid "ID"
-msgstr ""
+msgstr "标识"
 
-#, fuzzy
 msgctxt "field:res.user.warning,name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:res.user.warning,rec_name:"
 msgid "Name"
-msgstr "Naam bijlage"
+msgstr "名称"
 
-#, fuzzy
 msgctxt "field:res.user.warning,user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "field:res.user.warning,write_date:"
 msgid "Write Date"
-msgstr ""
+msgstr "写入日期"
 
 msgctxt "field:res.user.warning,write_uid:"
 msgid "Write User"
-msgstr ""
+msgstr "写入帐号"
 
 msgctxt "help:ir.sequence.type,groups:"
 msgid "Groups allowed to edit the sequences of this type"
-msgstr ""
+msgstr "允许编辑此类序列的用户组"
 
 msgctxt "help:res.user,actions:"
 msgid "Actions that will be run at login"
-msgstr ""
+msgstr "用户登录自动运行的操作"
 
-#, fuzzy
 msgctxt "model:ir.action,name:act_group_form"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "model:ir.action,name:act_user_config"
 msgid "Configure Users"
-msgstr ""
+msgstr "配置用户"
 
-#, fuzzy
 msgctxt "model:ir.action,name:act_user_form"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
 msgctxt "model:ir.action-res.group,name:"
 msgid "Action - Group"
-msgstr ""
+msgstr "操作-用户组"
 
 msgctxt "model:ir.cron,name:cron_trigger_time"
 msgid "Run On Time Triggers"
-msgstr ""
+msgstr "时基触发器"
 
 msgctxt "model:ir.model.button-res.group,name:"
 msgid "Model Button - Group"
-msgstr ""
+msgstr "模型按钮-用户组"
 
 msgctxt "model:ir.model.field-res.group,name:"
 msgid "Model Field Group Rel"
-msgstr ""
+msgstr "模型数据组 参考"
 
 msgctxt "model:ir.rule.group-res.group,name:"
 msgid "Rule Group - Group"
-msgstr ""
+msgstr "规则组 - 用户组"
 
 msgctxt "model:ir.rule.group-res.user,name:"
 msgid "Rule Group - User"
-msgstr ""
+msgstr "规则组 - 用户"
 
 msgctxt "model:ir.sequence.type-res.group,name:"
 msgid "Sequence Type - Group"
-msgstr ""
+msgstr "序列类别 - 用户组"
 
-#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_group_form"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_res"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
-#, fuzzy
 msgctxt "model:ir.ui.menu,name:menu_user_form"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
 msgctxt "model:ir.ui.menu-res.group,name:"
 msgid "UI Menu - Group"
-msgstr ""
+msgstr "菜单 - 用户组"
 
-#, fuzzy
 msgctxt "model:res.group,name:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "model:res.group,name:group_admin"
 msgid "Administration"
-msgstr "Systeembeheer"
+msgstr "管理员"
 
-#, fuzzy
 msgctxt "model:res.user,name:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "用户"
 
 msgctxt "model:res.user,name:user_admin"
 msgid "Administrator"
-msgstr ""
+msgstr "Administrator"
 
 msgctxt "model:res.user,name:user_trigger"
 msgid "Cron Trigger"
-msgstr ""
+msgstr "Cron 触发"
 
 msgctxt "model:res.user-ir.action,name:"
 msgid "User - Action"
-msgstr ""
+msgstr "用户 - 操作"
 
 msgctxt "model:res.user-res.group,name:"
 msgid "User - Group"
-msgstr ""
+msgstr "用户 - 用户组"
 
 msgctxt "model:res.user.config.start,name:"
 msgid "User Config Init"
-msgstr ""
+msgstr "用户init配置"
 
 msgctxt "model:res.user.login.attempt,name:"
 msgid "Login Attempt"
-msgstr ""
+msgstr "登录次数"
 
 msgctxt "model:res.user.warning,name:"
 msgid "User Warning"
-msgstr ""
+msgstr "用户警告"
 
 msgctxt "view:res.group:"
 msgid "Access Permissions"
-msgstr ""
+msgstr "操作权限"
 
-#, fuzzy
 msgctxt "view:res.group:"
 msgid "Group"
-msgstr "Groep"
+msgstr "用户组"
 
-#, fuzzy
 msgctxt "view:res.group:"
 msgid "Groups"
-msgstr "Groepen"
+msgstr "用户组"
 
 msgctxt "view:res.group:"
 msgid "Members"
-msgstr ""
+msgstr "成员"
 
 msgctxt "view:res.user.config.start:"
 msgid "Add Users"
-msgstr ""
+msgstr "添加用户"
 
 msgctxt "view:res.user.config.start:"
 msgid "Be careful that the login must be unique!"
-msgstr ""
+msgstr "用户组标识必须唯一!"
 
 msgctxt "view:res.user.config.start:"
 msgid "You can now add some users into the system."
-msgstr ""
+msgstr "现在可以给系统添加用户了."
 
-#, fuzzy
 msgctxt "view:res.user.warning:"
 msgid "Warning"
-msgstr "Waarschuwing"
+msgstr "警告"
 
 msgctxt "view:res.user.warning:"
 msgid "Warnings"
-msgstr ""
+msgstr "警告"
 
 msgctxt "view:res.user:"
 msgid "Access Permissions"
-msgstr ""
+msgstr "操作权限"
 
-#, fuzzy
 msgctxt "view:res.user:"
 msgid "Actions"
-msgstr "Acties"
+msgstr "动作"
 
 msgctxt "view:res.user:"
 msgid "Group Membership"
-msgstr ""
+msgstr "用户组"
 
 msgctxt "view:res.user:"
 msgid "Preferences"
-msgstr ""
+msgstr "偏好"
 
-#, fuzzy
 msgctxt "view:res.user:"
 msgid "User"
-msgstr "Gebruiker"
+msgstr "基本信息"
 
-#, fuzzy
 msgctxt "view:res.user:"
 msgid "Users"
-msgstr "Gebruikers"
+msgstr "用户"
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,start,end:"
 msgid "Cancel"
-msgstr "Annuleren"
+msgstr "取消"
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,start,user:"
 msgid "OK"
-msgstr "Oké"
+msgstr "确定"
 
-#, fuzzy
 msgctxt "wizard_button:res.user.config,user,add:"
 msgid "Add"
-msgstr "Toevoegen"
+msgstr "添加"
 
 msgctxt "wizard_button:res.user.config,user,end:"
 msgid "End"
-msgstr ""
+msgstr "完成"
diff --git a/trytond/res/user.py b/trytond/res/user.py
index 7fd6f60..64d500b 100644
--- a/trytond/res/user.py
+++ b/trytond/res/user.py
@@ -113,9 +113,9 @@ class User(ModelSQL, ModelView):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         super(User, cls).__register__(module_name)
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 1.6
 
@@ -244,7 +244,7 @@ class User(ModelSQL, ModelView):
             args.extend((users, cls._convert_vals(values)))
         super(User, cls).write(*args)
         # Clean cursor cache as it could be filled by domain_get
-        for cache in Transaction().cursor.cache.itervalues():
+        for cache in Transaction().cache.itervalues():
             if cls.__name__ in cache:
                 for user in all_users:
                     if user.id in cache[cls.__name__]:
@@ -451,7 +451,7 @@ class User(ModelSQL, ModelView):
         result = cls._get_login_cache.get(login)
         if result:
             return result
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         cursor.execute(*table.select(table.id, table.password_hash,
                 where=(table.login == login) & (table.active == True)))
@@ -495,20 +495,21 @@ class User(ModelSQL, ModelView):
 
     @classmethod
     def hash_sha1(cls, password):
-        if isinstance(password, unicode):
-            password = password.encode('utf-8')
         salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
-        hash_ = hashlib.sha1(password + salt).hexdigest()
+        salted_password = password + salt
+        if isinstance(salted_password, unicode):
+            salted_password = salted_password.encode('utf-8')
+        hash_ = hashlib.sha1(salted_password).hexdigest()
         return '$'.join(['sha1', hash_, salt])
 
     @classmethod
     def check_sha1(cls, password, hash_):
         if isinstance(password, unicode):
             password = password.encode('utf-8')
-        if isinstance(hash_, unicode):
-            hash_ = hash_.encode('utf-8')
         hash_method, hash_, salt = hash_.split('$', 2)
         salt = salt or ''
+        if isinstance(salt, unicode):
+            salt = salt.encode('utf-8')
         assert hash_method == 'sha1'
         return hash_ == hashlib.sha1(password + salt).hexdigest()
 
@@ -516,16 +517,16 @@ class User(ModelSQL, ModelView):
     def hash_bcrypt(cls, password):
         if isinstance(password, unicode):
             password = password.encode('utf-8')
-        hash_ = bcrypt.hashpw(password, bcrypt.gensalt())
+        hash_ = bcrypt.hashpw(password, bcrypt.gensalt()).decode('utf-8')
         return '$'.join(['bcrypt', hash_])
 
     @classmethod
     def check_bcrypt(cls, password, hash_):
         if isinstance(password, unicode):
             password = password.encode('utf-8')
+        hash_method, hash_ = hash_.split('$', 1)
         if isinstance(hash_, unicode):
             hash_ = hash_.encode('utf-8')
-        hash_method, hash_ = hash_.split('$', 1)
         assert hash_method == 'bcrypt'
         return hash_ == bcrypt.hashpw(password, hash_)
 
@@ -543,7 +544,7 @@ class LoginAttempt(ModelSQL):
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
         super(LoginAttempt, cls).__register__(module_name)
-        table = TableHandler(Transaction().cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
 
         # Migration from 2.8: remove user
         table.drop_column('user')
@@ -562,22 +563,23 @@ class LoginAttempt(ModelSQL):
     @classmethod
     @_login_size
     def add(cls, login):
-        cls.delete(cls.search([
-                    ('create_date', '<', cls.delay()),
-                    ]))
+        cursor = Transaction().connection.cursor()
+        table = cls.__table__()
+        cursor.execute(*table.delete(where=table.create_date < cls.delay()))
+
         cls.create([{'login': login}])
 
     @classmethod
     @_login_size
     def remove(cls, login):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         cursor.execute(*table.delete(where=table.login == login))
 
     @classmethod
     @_login_size
     def count(cls, login):
-        cursor = Transaction().cursor
+        cursor = Transaction().connection.cursor()
         table = cls.__table__()
         cursor.execute(*table.select(Count(Literal(1)),
                 where=(table.login == login)
@@ -629,13 +631,12 @@ class UserGroup(ModelSQL):
     @classmethod
     def __register__(cls, module_name):
         TableHandler = backend.get('TableHandler')
-        cursor = Transaction().cursor
         # Migration from 1.0 table name change
-        TableHandler.table_rename(cursor, 'res_group_user_rel', cls._table)
-        TableHandler.sequence_rename(cursor, 'res_group_user_rel_id_seq',
+        TableHandler.table_rename('res_group_user_rel', cls._table)
+        TableHandler.sequence_rename('res_group_user_rel_id_seq',
             cls._table + '_id_seq')
         # Migration from 2.0 uid and gid rename into user and group
-        table = TableHandler(cursor, cls, module_name)
+        table = TableHandler(cls, module_name)
         table.column_rename('uid', 'user')
         table.column_rename('gid', 'group')
         super(UserGroup, cls).__register__(module_name)
diff --git a/trytond/security.py b/trytond/security.py
index 70d594e..c874c7c 100644
--- a/trytond/security.py
+++ b/trytond/security.py
@@ -8,7 +8,7 @@ except ImportError:
 from trytond.pool import Pool
 from trytond.config import config
 from trytond.transaction import Transaction
-from trytond.exceptions import NotLogged
+from trytond import backend
 
 
 def _get_pool(dbname):
@@ -20,24 +20,22 @@ def _get_pool(dbname):
 
 
 def login(dbname, loginname, password, cache=True):
-    with Transaction().start(dbname, 0) as transaction:
+    with Transaction().start(dbname, 0):
         pool = _get_pool(dbname)
         User = pool.get('res.user')
         user_id = User.get_login(loginname, password)
-        transaction.cursor.commit()
     if user_id:
         if not cache:
             return user_id
-        with Transaction().start(dbname, user_id) as transaction:
+        with Transaction().start(dbname, user_id):
             Session = pool.get('ir.session')
             session, = Session.create([{}])
-            transaction.cursor.commit()
             return user_id, session.key
-    return False
+    return
 
 
 def logout(dbname, user, session):
-    with Transaction().start(dbname, 0) as transaction:
+    with Transaction().start(dbname, 0):
         pool = _get_pool(dbname)
         Session = pool.get('ir.session')
         sessions = Session.search([
@@ -48,7 +46,6 @@ def logout(dbname, user, session):
         session, = sessions
         name = session.create_uid.login
         Session.delete(sessions)
-        transaction.cursor.commit()
     return name
 
 
@@ -60,17 +57,19 @@ def check_super(passwd):
 
 
 def check(dbname, user, session):
-    if user == 0:
-        raise Exception('AccessDenied')
-    if not user:
-        raise NotLogged()
-    with Transaction().start(dbname, user) as transaction:
-        pool = _get_pool(dbname)
-        Session = pool.get('ir.session')
-        try:
-            if not Session.check(user, session):
-                raise NotLogged()
-            else:
-                return user
-        finally:
-            transaction.cursor.commit()
+    DatabaseOperationalError = backend.get('DatabaseOperationalError')
+    for count in range(config.getint('database', 'retry'), -1, -1):
+        with Transaction().start(dbname, user) as transaction:
+            pool = _get_pool(dbname)
+            Session = pool.get('ir.session')
+            try:
+                if not Session.check(user, session):
+                    return
+                else:
+                    return user
+            except DatabaseOperationalError:
+                if count:
+                    continue
+                raise
+            finally:
+                transaction.commit()
diff --git a/trytond/sendmail.py b/trytond/sendmail.py
new file mode 100644
index 0000000..cdc5d6e
--- /dev/null
+++ b/trytond/sendmail.py
@@ -0,0 +1,104 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import logging
+import smtplib
+import urllib
+from email.message import Message
+
+from .config import config, parse_uri
+from .transaction import Transaction
+
+__all__ = ['sendmail_transactional', 'sendmail', 'SMTPDataManager']
+logger = logging.getLogger(__name__)
+
+
+def sendmail_transactional(
+        from_addr, to_addrs, msg, transaction=None, datamanager=None):
+    if transaction is None:
+        transaction = Transaction()
+    assert isinstance(transaction, Transaction), transaction
+    if datamanager is None:
+        datamanager = SMTPDataManager()
+    datamanager = transaction.join(datamanager)
+    datamanager.put(from_addr, to_addrs, msg)
+
+
+def sendmail(from_addr, to_addrs, msg, server=None):
+    if server is None:
+        server = get_smtp_server()
+        quit = True
+    else:
+        quit = False
+    try:
+        senderrs = server.sendmail(from_addr, to_addrs, msg.as_string())
+    except smtplib.SMTPException:
+        logger.error('fail to send email', exc_info=True)
+    if senderrs:
+        logger.warn('fail to send email to %s', senderrs)
+    if quit:
+        server.quit()
+
+
+def get_smtp_server(uri=None):
+    if uri is None:
+        uri = config.get('email', 'uri')
+    uri = parse_uri(uri)
+    if uri.scheme.startswith('smtps'):
+        server = smtplib.SMTP_SSL(uri.hostname, uri.port)
+    else:
+        server = smtplib.SMTP(uri.hostname, uri.port)
+
+    if 'tls' in uri.scheme:
+        server.starttls()
+
+    if uri.username and uri.password:
+        server.login(
+            urllib.unquote_plus(uri.username),
+            urllib.unquote_plus(uri.password))
+    return server
+
+
+class SMTPDataManager(object):
+
+    def __init__(self, uri=None):
+        self.uri = uri
+        self.queue = []
+        self._server = None
+
+    def put(self, from_addr, to_addrs, msg):
+        assert isinstance(msg, Message), msg
+        self.queue.append((from_addr, to_addrs, msg))
+
+    def __eq__(self, other):
+        if not isinstance(other, SMTPDataManager):
+            return NotImplemented
+        return self.uri == other.uri
+
+    def abort(self, trans):
+        self._finish()
+
+    def tpc_begin(self, trans):
+        pass
+
+    def commit(self, trans):
+        pass
+
+    def tpc_vote(self, trans):
+        if self._server is None:
+            self._server = get_smtp_server(self.uri)
+
+    def tpc_finish(self, trans):
+        if self._server is not None:
+            for from_addr, to_addrs, msg in self.queue:
+                sendmail(from_addr, to_addrs, msg, server=self._server)
+            self._server.quit()
+            self._finish()
+
+    def tpc_abort(self, trans):
+        if self._server:
+            self._server.close()
+        self._finish()
+
+    def _finish(self):
+        self._server = None
+        self.queue = []
diff --git a/trytond/server.py b/trytond/server.py
deleted file mode 100644
index e75f6f3..0000000
--- a/trytond/server.py
+++ /dev/null
@@ -1,235 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-"""
-%prog [options]
-"""
-import logging
-import logging.config
-import logging.handlers
-import sys
-import os
-import signal
-import time
-from getpass import getpass
-import threading
-
-from sql import Table
-
-from trytond.config import config, parse_listen
-from trytond import backend
-from trytond.pool import Pool
-from trytond.monitor import monitor
-from .transaction import Transaction
-
-
-class TrytonServer(object):
-
-    def __init__(self, options):
-
-        config.update_etc(options.configfile)
-
-        if options.logconf:
-            logging.config.fileConfig(options.logconf)
-            logging.getLogger('server').info('using %s as logging '
-                'configuration file', options.logconf)
-        else:
-            logformat = ('%(process)s %(thread)s [%(asctime)s] '
-                '%(levelname)s %(name)s %(message)s')
-            if options.verbose:
-                if options.dev:
-                    level = logging.DEBUG
-                else:
-                    level = logging.INFO
-            else:
-                level = logging.ERROR
-            logging.basicConfig(level=level, format=logformat)
-
-        self.logger = logging.getLogger(__name__)
-
-        if options.configfile:
-            self.logger.info('using %s as configuration file',
-                options.configfile)
-        else:
-            self.logger.info('using default configuration')
-        self.logger.info('initialising distributed objects services')
-        self.xmlrpcd = []
-        self.jsonrpcd = []
-        self.webdavd = []
-        self.options = options
-
-        if time.tzname[0] != 'UTC':
-            self.logger.error('timezone is not set to UTC')
-
-    def run(self):
-        "Run the server and never return"
-        init = {}
-
-        signal.signal(signal.SIGINT, lambda *a: self.stop())
-        signal.signal(signal.SIGTERM, lambda *a: self.stop())
-        if hasattr(signal, 'SIGQUIT'):
-            signal.signal(signal.SIGQUIT, lambda *a: self.stop())
-        if hasattr(signal, 'SIGUSR1'):
-            signal.signal(signal.SIGUSR1, lambda *a: self.restart())
-
-        if self.options.pidfile:
-            with open(self.options.pidfile, 'w') as fd_pid:
-                fd_pid.write("%d" % (os.getpid()))
-
-        if not self.options.update:
-            self.start_servers()
-
-        for db_name in self.options.database_names:
-            init[db_name] = False
-            try:
-                with Transaction().start(db_name, 0) as transaction:
-                    cursor = transaction.cursor
-                    if self.options.update:
-                        if not cursor.test():
-                            self.logger.info("init db")
-                            backend.get('Database').init(cursor)
-                            init[db_name] = True
-                        cursor.commit()
-                    elif not cursor.test():
-                        raise Exception("'%s' is not a Tryton database!" %
-                            db_name)
-            except Exception:
-                self.stop(False)
-                raise
-
-        for db_name in self.options.database_names:
-            if self.options.update:
-                with Transaction().start(db_name, 0) as transaction:
-                    cursor = transaction.cursor
-                    if not cursor.test():
-                        raise Exception("'%s' is not a Tryton database!"
-                            % db_name)
-                    lang = Table('ir_lang')
-                    cursor.execute(*lang.select(lang.code,
-                            where=lang.translatable == True))
-                    lang = [x[0] for x in cursor.fetchall()]
-            else:
-                lang = None
-            Pool(db_name).init(update=self.options.update, lang=lang)
-
-        for db_name in self.options.database_names:
-            if init[db_name]:
-                # try to read password from environment variable
-                # TRYTONPASSFILE, empty TRYTONPASSFILE ignored
-                passpath = os.getenv('TRYTONPASSFILE')
-                password = ''
-                if passpath:
-                    try:
-                        with open(passpath) as passfile:
-                            password = passfile.readline()[:-1]
-                    except Exception, err:
-                        sys.stderr.write('Can not read password '
-                            'from "%s": "%s"\n' % (passpath, err))
-
-                if not password:
-                    while True:
-                        password = getpass('Admin Password for %s: ' % db_name)
-                        password2 = getpass('Admin Password Confirmation: ')
-                        if password != password2:
-                            sys.stderr.write('Admin Password Confirmation '
-                                'doesn\'t match Admin Password!\n')
-                            continue
-                        if not password:
-                            sys.stderr.write('Admin Password is required!\n')
-                            continue
-                        break
-
-                with Transaction().start(db_name, 0) as transaction:
-                    pool = Pool()
-                    User = pool.get('res.user')
-                    admin, = User.search([('login', '=', 'admin')])
-                    User.write([admin], {
-                            'password': password,
-                            })
-                    transaction.cursor.commit()
-
-        if self.options.update:
-            self.logger.info('Update/Init succeed!')
-            logging.shutdown()
-            sys.exit(0)
-
-        threads = {}
-        while True:
-            if self.options.cron:
-                for dbname in Pool.database_list():
-                    thread = threads.get(dbname)
-                    if thread and thread.is_alive():
-                        continue
-                    pool = Pool(dbname)
-                    if not pool.lock.acquire(0):
-                        continue
-                    try:
-                        try:
-                            Cron = pool.get('ir.cron')
-                        except KeyError:
-                            continue
-                    finally:
-                        pool.lock.release()
-                    thread = threading.Thread(
-                            target=Cron.run,
-                            args=(dbname,), kwargs={})
-                    thread.start()
-                    threads[dbname] = thread
-            if self.options.dev:
-                for _ in range(60):
-                    if monitor([self.options.configfile]
-                            if self.options.configfile else []):
-                        self.restart()
-                    time.sleep(1)
-            else:
-                time.sleep(60)
-
-    def start_servers(self):
-        ssl = config.get('ssl', 'privatekey')
-        # Launch Server
-        if config.get('jsonrpc', 'listen'):
-            from trytond.protocols.jsonrpc import JSONRPCDaemon
-            for hostname, port in parse_listen(
-                    config.get('jsonrpc', 'listen')):
-                self.jsonrpcd.append(JSONRPCDaemon(hostname, port, ssl))
-                self.logger.info("starting JSON-RPC%s protocol on %s:%d",
-                    ssl and ' SSL' or '', hostname or '*', port)
-
-        if config.get('xmlrpc', 'listen'):
-            from trytond.protocols.xmlrpc import XMLRPCDaemon
-            for hostname, port in parse_listen(
-                    config.get('xmlrpc', 'listen')):
-                self.xmlrpcd.append(XMLRPCDaemon(hostname, port, ssl))
-                self.logger.info("starting XML-RPC%s protocol on %s:%d",
-                    ssl and ' SSL' or '', hostname or '*', port)
-
-        if config.get('webdav', 'listen'):
-            from trytond.protocols.webdav import WebDAVServerThread
-            for hostname, port in parse_listen(
-                    config.get('webdav', 'listen')):
-                self.webdavd.append(WebDAVServerThread(hostname, port, ssl))
-                self.logger.info("starting WebDAV%s protocol on %s:%d",
-                    ssl and ' SSL' or '', hostname or '*', port)
-
-        for servers in (self.xmlrpcd, self.jsonrpcd, self.webdavd):
-            for server in servers:
-                server.start()
-
-    def stop(self, exit=True):
-        for servers in (self.xmlrpcd, self.jsonrpcd, self.webdavd):
-            for server in servers:
-                server.stop()
-                server.join()
-        if exit:
-            if self.options.pidfile:
-                os.unlink(self.options.pidfile)
-            logging.getLogger('server').info('stopped')
-            logging.shutdown()
-            sys.exit(0)
-
-    def restart(self):
-        self.stop(False)
-        args = ([sys.executable] + ['-W%s' % o for o in sys.warnoptions]
-            + sys.argv)
-        if sys.platform == "win32":
-            args = ['"%s"' % arg for arg in args]
-        os.execv(sys.executable, args)
diff --git a/trytond/tests/__init__.py b/trytond/tests/__init__.py
index f841378..a16f4c2 100644
--- a/trytond/tests/__init__.py
+++ b/trytond/tests/__init__.py
@@ -86,6 +86,8 @@ def register():
         Many2ManySize,
         Many2ManySizeTarget,
         Many2ManySizeRelation,
+        Many2ManyTree,
+        Many2ManyTreeRelation,
         Reference,
         ReferenceTarget,
         ReferenceRequired,
@@ -104,6 +106,7 @@ def register():
         ModelStorage,
         ModelSQLRequiredField,
         ModelSQLTimestamp,
+        ModelSQLFieldSet,
         Model4Union1,
         Model4Union2,
         Model4Union3,
@@ -160,6 +163,8 @@ def register():
         Many2OneDomainValidation,
         Many2OneOrderBy,
         Many2OneSearch,
+        Many2OneTree,
+        Many2OneMPTT,
         TestHistory,
         TestHistoryLine,
         FieldContextChild,
diff --git a/trytond/tests/export_data.py b/trytond/tests/export_data.py
index e084c2b..422e6b2 100644
--- a/trytond/tests/export_data.py
+++ b/trytond/tests/export_data.py
@@ -7,7 +7,6 @@ from trytond.pool import PoolMeta
 __all__ = [
     'ExportDataTarget', 'ExportData', 'ExportDataTarget2',
     'ExportDataRelation']
-__metaclass__ = PoolMeta
 
 
 class ExportDataTarget(ModelSQL):
@@ -46,6 +45,7 @@ class ExportData(ModelSQL):
 
 class ExportDataTarget2:
     'Export Date Target'
+    __metaclass__ = PoolMeta
     __name__ = 'test.export_data.target'
     one2many = fields.Many2One('test.export_data', 'Export Data')
 
diff --git a/trytond/tests/history.py b/trytond/tests/history.py
index 6421ad8..f94bd01 100644
--- a/trytond/tests/history.py
+++ b/trytond/tests/history.py
@@ -11,6 +11,10 @@ class TestHistory(ModelSQL):
     _history = True
     value = fields.Integer('Value')
     lines = fields.One2Many('test.history.line', 'history', 'Lines')
+    lines_at_stamp = fields.One2Many(
+        'test.history.line', 'history', 'Lines at Stamp',
+        datetime_field='stamp')
+    stamp = fields.Timestamp('Stamp')
 
 
 class TestHistoryLine(ModelSQL):
diff --git a/trytond/tests/model.py b/trytond/tests/model.py
index 835eb99..c0d1730 100644
--- a/trytond/tests/model.py
+++ b/trytond/tests/model.py
@@ -5,7 +5,7 @@ from trytond.model import ModelSingleton, ModelSQL, UnionMixin, fields
 __all__ = [
     'Singleton', 'URLObject',
     'ModelStorage',
-    'ModelSQLRequiredField', 'ModelSQLTimestamp',
+    'ModelSQLRequiredField', 'ModelSQLTimestamp', 'ModelSQLFieldSet',
     'Model4Union1', 'Model4Union2', 'Model4Union3', 'Model4Union4',
     'Union', 'UnionUnion',
     'Model4UnionTree1', 'Model4UnionTree2', 'UnionTree',
@@ -47,6 +47,21 @@ class ModelSQLTimestamp(ModelSQL):
     __name__ = 'test.modelsql.timestamp'
 
 
+class ModelSQLFieldSet(ModelSQL):
+    'Model to test field set'
+    __name__ = 'test.modelsql.field_set'
+
+    field = fields.Function(fields.Integer('Field'),
+        'get_field', setter='set_field')
+
+    def get_field(self, name=None):
+        return
+
+    @classmethod
+    def set_field(cls, records, name, value):
+        pass
+
+
 class Model4Union1(ModelSQL):
     'Model for union 1'
     __name__ = 'test.model.union1'
diff --git a/trytond/tests/run-tests.py b/trytond/tests/run-tests.py
index 1bbc3a9..cac56a2 100755
--- a/trytond/tests/run-tests.py
+++ b/trytond/tests/run-tests.py
@@ -18,6 +18,8 @@ logging.basicConfig(level=logging.ERROR)
 parser = argparse.ArgumentParser()
 parser.add_argument("-c", "--config", dest="config",
     help="specify config file")
+parser.add_argument("-f", "--failfast", action="store_true", dest="failfast",
+    help="Stop the test run on the first error or failure")
 parser.add_argument("-m", "--modules", action="store_true", dest="modules",
     default=False, help="Run also modules tests")
 parser.add_argument("--no-doctest", action="store_false", dest="doctest",
@@ -42,5 +44,6 @@ if not opt.modules:
     suite = all_suite(opt.tests)
 else:
     suite = modules_suite(opt.tests, doc=opt.doctest)
-result = unittest.TextTestRunner(verbosity=opt.verbosity).run(suite)
+result = unittest.TextTestRunner(
+    verbosity=opt.verbosity, failfast=opt.failfast).run(suite)
 sys.exit(not result.wasSuccessful())
diff --git a/trytond/tests/test.py b/trytond/tests/test.py
index b493a27..62a03a6 100644
--- a/trytond/tests/test.py
+++ b/trytond/tests/test.py
@@ -30,13 +30,14 @@ __all__ = [
     'Many2ManyReference', 'Many2ManyReferenceTarget',
     'Many2ManyReferenceRelation',
     'Many2ManySize', 'Many2ManySizeTarget', 'Many2ManySizeRelation',
+    'Many2ManyTree', 'Many2ManyTreeRelation',
     'Reference', 'ReferenceTarget', 'ReferenceRequired',
     'Property',
     'Selection', 'SelectionRequired',
     'DictSchema', 'Dict', 'DictDefault', 'DictRequired',
     'Binary', 'BinaryDefault', 'BinaryRequired',
     'Many2OneDomainValidation', 'Many2OneTarget', 'Many2OneOrderBy',
-    'Many2OneSearch',
+    'Many2OneSearch', 'Many2OneTree', 'Many2OneMPTT',
     ]
 
 
@@ -588,6 +589,22 @@ class Many2ManySizeRelation(ModelSQL):
     target = fields.Many2One('test.many2many_size.target', 'Target')
 
 
+class Many2ManyTree(ModelSQL):
+    'Many2Many Tree'
+    __name__ = 'test.many2many_tree'
+    parents = fields.Many2Many('test.many2many_tree.relation',
+        'child', 'parent', 'Parents')
+    children = fields.Many2Many('test.many2many_tree.relation',
+        'parent', 'child', 'Children')
+
+
+class Many2ManyTreeRelation(ModelSQL):
+    'Many2Many Tree Relation'
+    __name__ = 'test.many2many_tree.relation'
+    parent = fields.Many2One('test.many2many_tree', 'Parent')
+    child = fields.Many2One('test.many2many_tree', 'Child')
+
+
 class Reference(ModelSQL):
     'Reference'
     __name__ = 'test.reference'
@@ -744,3 +761,26 @@ class Many2OneSearch(ModelSQL):
     "Many2One Search"
     __name__ = 'test.many2one_search'
     many2one = fields.Many2One('test.many2one_target', 'many2one')
+
+
+class Many2OneTree(ModelSQL):
+    'Many2One Tree'
+    __name__ = 'test.many2one_tree'
+    many2one = fields.Many2One('test.many2one_tree', 'many2one')
+
+
+class Many2OneMPTT(ModelSQL):
+    'Many2One MPTT'
+    __name__ = 'test.many2one_mptt'
+    many2one = fields.Many2One('test.many2one_mptt', 'many2one',
+        left='left', right='right')
+    left = fields.Integer('Left', required=True)
+    right = fields.Integer('Right', required=True)
+
+    @classmethod
+    def default_left(cls):
+        return 0
+
+    @classmethod
+    def default_right(cls):
+        return 0
diff --git a/trytond/tests/test_access.py b/trytond/tests/test_access.py
index fc780c5..be67436 100644
--- a/trytond/tests/test_access.py
+++ b/trytond/tests/test_access.py
@@ -2,775 +2,780 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 import unittest
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.exceptions import UserError
 
-CONTEXT = CONTEXT.copy()
-CONTEXT['_check_access'] = True
+_context = {'_check_access': True}
 
 
 class ModelAccessTestCase(unittest.TestCase):
     'Test Model Access'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.model_access = POOL.get('ir.model.access')
-        self.test_access = POOL.get('test.access')
-        self.model = POOL.get('ir.model')
-        self.group = POOL.get('res.group')
 
-    def test0010perm_read(self):
+    @with_transaction(context=_context)
+    def test_perm_read(self):
         'Test Read Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([('model', '=', 'test.access')])
-
-            test, = self.test_access.create([{}])
-
-            # Without model access
-            self.test_access.read([test.id])
-
-            # With model access
-
-            # One access allowed for any group
-            model_access_wo_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': None,
-                        'perm_read': True,
-                        }])
-            self.test_access.read([test.id])
-
-            # One access disallowed for any group
-            self.model_access.write([model_access_wo_group], {
-                    'perm_read': False,
-                    })
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-
-            # Two access rules with one group allowed
-            group, = self.group.search([('users', '=', USER)])
-            model_access_w_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': group.id,
-                        'perm_read': True,
-                        }])
-
-            self.test_access.read([test.id])
-
-            # Two access rules with both allowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_read': True,
-                    })
-            self.test_access.read([test.id])
-
-            # Two access rules with any group allowed
-            self.model_access.write([model_access_w_group], {
-                    'perm_read': False,
-                    })
-            self.test_access.read([test.id])
-
-            # Two access rules with both disallowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_read': False,
-                    })
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-
-            # One access disallowed for one group
-            self.model_access.delete([model_access_wo_group])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-
-            # One access allowed for one group
-            self.model_access.write([model_access_w_group], {
+        pool = Pool()
+        ModelAccess = pool.get('ir.model.access')
+        TestAccess = pool.get('test.access')
+        Model = pool.get('ir.model')
+        Group = pool.get('res.group')
+
+        model, = Model.search([('model', '=', 'test.access')])
+
+        test, = TestAccess.create([{}])
+
+        # Without model access
+        TestAccess.read([test.id])
+
+        # With model access
+
+        # One access allowed for any group
+        model_access_wo_group, = ModelAccess.create([{
+                    'model': model.id,
+                    'group': None,
                     'perm_read': True,
-                    })
-            self.test_access.read([test.id])
+                    }])
+        TestAccess.read([test.id])
 
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.model_access.write([model_access_w_group], {
+        # One access disallowed for any group
+        ModelAccess.write([model_access_wo_group], {
+                'perm_read': False,
+                })
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+
+        # Two access rules with one group allowed
+        group, = Group.search([('users', '=', Transaction().user)])
+        model_access_w_group, = ModelAccess.create([{
+                    'model': model.id,
                     'group': group.id,
-                    })
-            self.test_access.read([test.id])
+                    'perm_read': True,
+                    }])
 
-            # One access disallowed for one other group
-            self.model_access.write([model_access_w_group], {
-                    'perm_read': False,
-                    })
-            self.test_access.read([test.id])
+        TestAccess.read([test.id])
 
-            transaction.cursor.rollback()
-            self.model_access._get_access_cache.clear()
+        # Two access rules with both allowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_read': True,
+                })
+        TestAccess.read([test.id])
+
+        # Two access rules with any group allowed
+        ModelAccess.write([model_access_w_group], {
+                'perm_read': False,
+                })
+        TestAccess.read([test.id])
+
+        # Two access rules with both disallowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_read': False,
+                })
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+
+        # One access disallowed for one group
+        ModelAccess.delete([model_access_wo_group])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+
+        # One access allowed for one group
+        ModelAccess.write([model_access_w_group], {
+                'perm_read': True,
+                })
+        TestAccess.read([test.id])
 
-    def test0020perm_write(self):
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        ModelAccess.write([model_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.read([test.id])
+
+        # One access disallowed for one other group
+        ModelAccess.write([model_access_w_group], {
+                'perm_read': False,
+                })
+        TestAccess.read([test.id])
+
+    @with_transaction(context=_context)
+    def test_perm_write(self):
         'Test Write Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([('model', '=', 'test.access')])
-
-            test, = self.test_access.create([{}])
-
-            # Without model access
-            self.test_access.write([test], {})
-
-            # With model access
-
-            # One access allowed for any group
-            model_access_wo_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': None,
-                        'perm_write': True,
-                        }])
-            self.test_access.write([test], {})
-
-            # One access disallowed for any group
-            self.model_access.write([model_access_wo_group], {
-                    'perm_write': False,
-                    })
-            self.assertRaises(UserError, self.test_access.write, [test], {})
-
-            # Two access rules with one group allowed
-            group, = self.group.search([('users', '=', USER)])
-            model_access_w_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': group.id,
-                        'perm_write': True,
-                        }])
-            self.test_access.write([test], {})
-
-            # Two access rules with both allowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_write': True,
-                    })
-            self.test_access.write([test], {})
-
-            # Two access rules with any group allowed
-            self.model_access.write([model_access_w_group], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-
-            # Two access rules with both disallowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_write': False,
-                    })
-            self.assertRaises(UserError, self.test_access.write, [test], {})
-
-            # One access disallowed for one group
-            self.model_access.delete([model_access_wo_group])
-            self.assertRaises(UserError, self.test_access.write, [test], {})
-
-            # One access allowed for one group
-            self.model_access.write([model_access_w_group], {
+        pool = Pool()
+        ModelAccess = pool.get('ir.model.access')
+        TestAccess = pool.get('test.access')
+        Model = pool.get('ir.model')
+        Group = pool.get('res.group')
+
+        model, = Model.search([('model', '=', 'test.access')])
+
+        test, = TestAccess.create([{}])
+
+        # Without model access
+        TestAccess.write([test], {})
+
+        # With model access
+
+        # One access allowed for any group
+        model_access_wo_group, = ModelAccess.create([{
+                    'model': model.id,
+                    'group': None,
                     'perm_write': True,
-                    })
-            self.test_access.write([test], {})
+                    }])
+        TestAccess.write([test], {})
+
+        # One access disallowed for any group
+        ModelAccess.write([model_access_wo_group], {
+                'perm_write': False,
+                })
+        self.assertRaises(UserError, TestAccess.write, [test], {})
 
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.model_access.write([model_access_w_group], {
+        # Two access rules with one group allowed
+        group, = Group.search([('users', '=', Transaction().user)])
+        model_access_w_group, = ModelAccess.create([{
+                    'model': model.id,
                     'group': group.id,
-                    })
-            self.test_access.write([test], {})
+                    'perm_write': True,
+                    }])
+        TestAccess.write([test], {})
+
+        # Two access rules with both allowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_write': True,
+                })
+        TestAccess.write([test], {})
+
+        # Two access rules with any group allowed
+        ModelAccess.write([model_access_w_group], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+
+        # Two access rules with both disallowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_write': False,
+                })
+        self.assertRaises(UserError, TestAccess.write, [test], {})
 
-            # One access disallowed for one other group
-            self.model_access.write([model_access_w_group], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
+        # One access disallowed for one group
+        ModelAccess.delete([model_access_wo_group])
+        self.assertRaises(UserError, TestAccess.write, [test], {})
 
-            transaction.cursor.rollback()
-            self.model_access._get_access_cache.clear()
+        # One access allowed for one group
+        ModelAccess.write([model_access_w_group], {
+                'perm_write': True,
+                })
+        TestAccess.write([test], {})
+
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        ModelAccess.write([model_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.write([test], {})
 
-    def test0030perm_create(self):
+        # One access disallowed for one other group
+        ModelAccess.write([model_access_w_group], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+
+    @with_transaction(context=_context)
+    def test_perm_create(self):
         'Test Create Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([('model', '=', 'test.access')])
-
-            # Without model access
-            self.test_access.create([{}])
-
-            # With model access
-
-            # One access allowed for any group
-            model_access_wo_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': None,
-                        'perm_create': True,
-                        }])
-            self.test_access.create([{}])
-
-            # One access disallowed for any group
-            self.model_access.write([model_access_wo_group], {
-                    'perm_create': False,
-                    })
-            self.assertRaises(UserError, self.test_access.create, {})
-
-            # Two access rules with one group allowed
-            group, = self.group.search([('users', '=', USER)])
-            model_access_w_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': group.id,
-                        'perm_create': True,
-                        }])
-
-            self.test_access.create([{}])
-
-            # Two access rules with both allowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_create': True,
-                    })
-            self.test_access.create([{}])
-
-            # Two access rules with any group allowed
-            self.model_access.write([model_access_w_group], {
-                    'perm_create': False,
-                    })
-            self.test_access.create([{}])
-
-            # Two access rules with both disallowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_create': False,
-                    })
-            self.assertRaises(UserError, self.test_access.create, [{}])
-
-            # One access disallowed for one group
-            self.model_access.delete([model_access_wo_group])
-            self.assertRaises(UserError, self.test_access.create, [{}])
-
-            # One access allowed for one group
-            self.model_access.write([model_access_w_group], {
+        pool = Pool()
+        ModelAccess = pool.get('ir.model.access')
+        TestAccess = pool.get('test.access')
+        Model = pool.get('ir.model')
+        Group = pool.get('res.group')
+
+        model, = Model.search([('model', '=', 'test.access')])
+
+        # Without model access
+        TestAccess.create([{}])
+
+        # With model access
+
+        # One access allowed for any group
+        model_access_wo_group, = ModelAccess.create([{
+                    'model': model.id,
+                    'group': None,
                     'perm_create': True,
-                    })
-            self.test_access.create([{}])
+                    }])
+        TestAccess.create([{}])
 
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.model_access.write([model_access_w_group], {
+        # One access disallowed for any group
+        ModelAccess.write([model_access_wo_group], {
+                'perm_create': False,
+                })
+        self.assertRaises(UserError, TestAccess.create, {})
+
+        # Two access rules with one group allowed
+        group, = Group.search([('users', '=', Transaction().user)])
+        model_access_w_group, = ModelAccess.create([{
+                    'model': model.id,
                     'group': group.id,
-                    })
-            self.test_access.create([{}])
+                    'perm_create': True,
+                    }])
+
+        TestAccess.create([{}])
+
+        # Two access rules with both allowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_create': True,
+                })
+        TestAccess.create([{}])
 
-            # One access disallowed for one other group
-            self.model_access.write([model_access_w_group], {
-                    'perm_create': False,
-                    })
-            self.test_access.create([{}])
+        # Two access rules with any group allowed
+        ModelAccess.write([model_access_w_group], {
+                'perm_create': False,
+                })
+        TestAccess.create([{}])
+
+        # Two access rules with both disallowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_create': False,
+                })
+        self.assertRaises(UserError, TestAccess.create, [{}])
 
-            transaction.cursor.rollback()
-            self.model_access._get_access_cache.clear()
+        # One access disallowed for one group
+        ModelAccess.delete([model_access_wo_group])
+        self.assertRaises(UserError, TestAccess.create, [{}])
+
+        # One access allowed for one group
+        ModelAccess.write([model_access_w_group], {
+                'perm_create': True,
+                })
+        TestAccess.create([{}])
 
-    def test0040perm_delete(self):
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        ModelAccess.write([model_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.create([{}])
+
+        # One access disallowed for one other group
+        ModelAccess.write([model_access_w_group], {
+                'perm_create': False,
+                })
+        TestAccess.create([{}])
+
+    @with_transaction(context=_context)
+    def test_perm_delete(self):
         'Test Delete Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([('model', '=', 'test.access')])
-
-            tests = [self.test_access.create([{}])[0] for x in range(11)]
-
-            # Without model access
-            self.test_access.delete([tests.pop()])
-
-            # With model access
-
-            # One access allowed for any group
-            model_access_wo_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': None,
-                        'perm_delete': True,
-                        }])
-            self.test_access.delete([tests.pop()])
-
-            # One access disallowed for any group
-            self.model_access.write([model_access_wo_group], {
-                    'perm_delete': False,
-                    })
-            self.assertRaises(UserError, self.test_access.delete,
-                [tests.pop()])
-
-            # Two access rules with one group allowed
-            group = self.group.search([('users', '=', USER)])[0]
-            model_access_w_group, = self.model_access.create([{
-                        'model': model.id,
-                        'group': group.id,
-                        'perm_delete': True,
-                        }])
-
-            self.test_access.delete([tests.pop()])
-
-            # Two access rules with both allowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_delete': True,
-                    })
-            self.test_access.delete([tests.pop()])
-
-            # Two access rules with any group allowed
-            self.model_access.write([model_access_w_group], {
-                    'perm_delete': False,
-                    })
-            self.test_access.delete([tests.pop()])
-
-            # Two access rules with both disallowed
-            self.model_access.write([model_access_wo_group], {
-                    'perm_delete': False,
-                    })
-            self.assertRaises(UserError, self.test_access.delete,
-                [tests.pop()])
-
-            # One access disallowed for one group
-            self.model_access.delete([model_access_wo_group])
-            self.assertRaises(UserError, self.test_access.delete,
-                [tests.pop()])
-
-            # One access allowed for one group
-            self.model_access.write([model_access_w_group], {
+        pool = Pool()
+        ModelAccess = pool.get('ir.model.access')
+        TestAccess = pool.get('test.access')
+        Model = pool.get('ir.model')
+        Group = pool.get('res.group')
+
+        model, = Model.search([('model', '=', 'test.access')])
+
+        tests = [TestAccess.create([{}])[0] for x in range(11)]
+
+        # Without model access
+        TestAccess.delete([tests.pop()])
+
+        # With model access
+
+        # One access allowed for any group
+        model_access_wo_group, = ModelAccess.create([{
+                    'model': model.id,
+                    'group': None,
                     'perm_delete': True,
-                    })
-            self.test_access.delete([tests.pop()])
+                    }])
+        TestAccess.delete([tests.pop()])
 
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.model_access.write([model_access_w_group], {
+        # One access disallowed for any group
+        ModelAccess.write([model_access_wo_group], {
+                'perm_delete': False,
+                })
+        self.assertRaises(UserError, TestAccess.delete, [tests.pop()])
+
+        # Two access rules with one group allowed
+        group = Group.search([('users', '=', Transaction().user)])[0]
+        model_access_w_group, = ModelAccess.create([{
+                    'model': model.id,
                     'group': group.id,
-                    })
-            self.test_access.delete([tests.pop()])
+                    'perm_delete': True,
+                    }])
+
+        TestAccess.delete([tests.pop()])
+
+        # Two access rules with both allowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_delete': True,
+                })
+        TestAccess.delete([tests.pop()])
+
+        # Two access rules with any group allowed
+        ModelAccess.write([model_access_w_group], {
+                'perm_delete': False,
+                })
+        TestAccess.delete([tests.pop()])
+
+        # Two access rules with both disallowed
+        ModelAccess.write([model_access_wo_group], {
+                'perm_delete': False,
+                })
+        self.assertRaises(UserError, TestAccess.delete, [tests.pop()])
 
-            # One access disallowed for one other group
-            self.model_access.write([model_access_w_group], {
-                    'perm_delete': False,
-                    })
-            self.test_access.delete([tests.pop()])
+        # One access disallowed for one group
+        ModelAccess.delete([model_access_wo_group])
+        self.assertRaises(UserError, TestAccess.delete, [tests.pop()])
 
-            transaction.cursor.rollback()
-            self.model_access._get_access_cache.clear()
+        # One access allowed for one group
+        ModelAccess.write([model_access_w_group], {
+                'perm_delete': True,
+                })
+        TestAccess.delete([tests.pop()])
+
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        ModelAccess.write([model_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.delete([tests.pop()])
+
+        # One access disallowed for one other group
+        ModelAccess.write([model_access_w_group], {
+                'perm_delete': False,
+                })
+        TestAccess.delete([tests.pop()])
 
 
 class ModelFieldAccessTestCase(unittest.TestCase):
     'Test Model Field Access'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.field_access = POOL.get('ir.model.field.access')
-        self.test_access = POOL.get('test.access')
-        self.field = POOL.get('ir.model.field')
-        self.group = POOL.get('res.group')
 
+    @with_transaction(context=_context)
     def test0010perm_read(self):
         'Test Read Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            field1, = self.field.search([
-                    ('model.model', '=', 'test.access'),
-                    ('name', '=', 'field1'),
-                    ])
-            field2, = self.field.search([
-                    ('model.model', '=', 'test.access'),
-                    ('name', '=', 'field2'),
-                    ])
-
-            test, = self.test_access.create([{
-                        'field1': 'ham',
-                        'field2': 'spam',
-                        }])
-
-            # Without field access
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # With field access
-
-            # One access allowed for any group
-            field_access_wo_group, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': None,
-                        'perm_read': True,
-                        }])
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # One access disallowed for any group
-            self.field_access.write([field_access_wo_group], {
-                    'perm_read': False,
-                    })
-
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-            self.assertRaises(UserError, getattr, test, 'field1')
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules with one group allowed
-            group = self.group.search([('users', '=', USER)])[0]
-            field_access_w_group, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': group.id,
-                        'perm_read': True,
-                        }])
-
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules with both allowed
-            self.field_access.write([field_access_wo_group], {
+        pool = Pool()
+        FieldAccess = pool.get('ir.model.field.access')
+        TestAccess = pool.get('test.access')
+        Field = pool.get('ir.model.field')
+        Group = pool.get('res.group')
+        transaction = Transaction()
+
+        field1, = Field.search([
+                ('model.model', '=', 'test.access'),
+                ('name', '=', 'field1'),
+                ])
+        field2, = Field.search([
+                ('model.model', '=', 'test.access'),
+                ('name', '=', 'field2'),
+                ])
+
+        test, = TestAccess.create([{
+                    'field1': 'ham',
+                    'field2': 'spam',
+                    }])
+
+        # Without field access
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # With field access
+
+        # One access allowed for any group
+        field_access_wo_group, = FieldAccess.create([{
+                    'field': field1.id,
+                    'group': None,
                     'perm_read': True,
-                    })
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules with any group allowed
-            self.field_access.write([field_access_w_group], {
-                    'perm_read': False,
-                    })
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules with both disallowed
-            self.field_access.write([field_access_wo_group], {
+                    }])
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # One access disallowed for any group
+        FieldAccess.write([field_access_wo_group], {
                 'perm_read': False,
                 })
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-            self.assertRaises(UserError, getattr, test, 'field1')
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # One access disallowed for one group
-            self.field_access.delete([field_access_wo_group])
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-            self.assertRaises(UserError, getattr, test, 'field1')
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # One access allowed for one group
-            self.field_access.write([field_access_w_group], {
-                    'perm_read': True,
-                    })
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.field_access.write([field_access_w_group], {
+
+        self.assertRaises(UserError, TestAccess.read, [test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+        self.assertRaises(UserError, getattr, test, 'field1')
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules with one group allowed
+        group = Group.search([('users', '=', transaction.user)])[0]
+        field_access_w_group, = FieldAccess.create([{
+                    'field': field1.id,
                     'group': group.id,
-                    })
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # One access disallowed for one other group
-            self.field_access.write([field_access_w_group], {
-                    'perm_read': False,
-                    })
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules on both fields allowed
-            self.field_access.delete([field_access_w_group])
-
-            field_access1, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': None,
-                        'perm_read': True,
-                        }])
-            field_access2, = self.field_access.create([{
-                        'field': field2.id,
-                        'group': None,
-                        'perm_read': True,
-                        }])
-
-            self.test_access.read([test.id], ['field1'])
-            self.test_access.read([test.id], ['field2'])
-            self.test_access.read([test.id])
-            test.field1
-            test.field2
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules on both fields one allowed and one disallowed
-            self.field_access.write([field_access2], {
+                    'perm_read': True,
+                    }])
+
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules with both allowed
+        FieldAccess.write([field_access_wo_group], {
+                'perm_read': True,
+                })
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules with any group allowed
+        FieldAccess.write([field_access_w_group], {
                 'perm_read': False,
                 })
-            self.test_access.read([test.id], ['field1'])
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field2'])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-            test.field1
-            self.assertRaises(UserError, getattr, test, 'field2')
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            # Two access rules on both fields disallowed
-            self.field_access.write([field_access1], {
-                    'perm_read': False,
-                    })
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field1'])
-            self.assertRaises(UserError, self.test_access.read, [test.id],
-                ['field2'])
-            self.assertRaises(UserError, self.test_access.read, [test.id])
-            self.assertRaises(UserError, getattr, test, 'field1')
-            self.assertRaises(UserError, getattr, test, 'field2')
-            transaction.cursor.cache.clear()
-            test = self.test_access(test.id)
-
-            transaction.cursor.rollback()
-            self.field_access._get_access_cache.clear()
-
-    def test0010perm_write(self):
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules with both disallowed
+        FieldAccess.write([field_access_wo_group], {
+            'perm_read': False,
+            })
+        self.assertRaises(UserError, TestAccess.read, [test.id],
+            ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+        self.assertRaises(UserError, getattr, test, 'field1')
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # One access disallowed for one group
+        FieldAccess.delete([field_access_wo_group])
+        self.assertRaises(UserError, TestAccess.read, [test.id],
+            ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+        self.assertRaises(UserError, getattr, test, 'field1')
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # One access allowed for one group
+        FieldAccess.write([field_access_w_group], {
+                'perm_read': True,
+                })
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        FieldAccess.write([field_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # One access disallowed for one other group
+        FieldAccess.write([field_access_w_group], {
+                'perm_read': False,
+                })
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules on both fields allowed
+        FieldAccess.delete([field_access_w_group])
+
+        field_access1, = FieldAccess.create([{
+                    'field': field1.id,
+                    'group': None,
+                    'perm_read': True,
+                    }])
+        field_access2, = FieldAccess.create([{
+                    'field': field2.id,
+                    'group': None,
+                    'perm_read': True,
+                    }])
+
+        TestAccess.read([test.id], ['field1'])
+        TestAccess.read([test.id], ['field2'])
+        TestAccess.read([test.id])
+        test.field1
+        test.field2
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules on both fields one allowed and one disallowed
+        FieldAccess.write([field_access2], {
+            'perm_read': False,
+            })
+        TestAccess.read([test.id], ['field1'])
+        self.assertRaises(UserError, TestAccess.read, [test.id],
+            ['field2'])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+        test.field1
+        self.assertRaises(UserError, getattr, test, 'field2')
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+        # Two access rules on both fields disallowed
+        FieldAccess.write([field_access1], {
+                'perm_read': False,
+                })
+        self.assertRaises(UserError, TestAccess.read, [test.id],
+            ['field1'])
+        self.assertRaises(UserError, TestAccess.read, [test.id],
+            ['field2'])
+        self.assertRaises(UserError, TestAccess.read, [test.id])
+        self.assertRaises(UserError, getattr, test, 'field1')
+        self.assertRaises(UserError, getattr, test, 'field2')
+        transaction.cache.clear()
+        test = TestAccess(test.id)
+
+    @with_transaction(context=_context)
+    def test_perm_write(self):
         'Test Write Access'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            field1, = self.field.search([
-                    ('model.model', '=', 'test.access'),
-                    ('name', '=', 'field1'),
-                    ])
-            field2, = self.field.search([
-                    ('model.model', '=', 'test.access'),
-                    ('name', '=', 'field2'),
-                    ])
-
-            test, = self.test_access.create([{
-                        'field1': 'ham',
-                        'field2': 'spam',
-                        }])
-
-            # Without field access
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-
-            # With field access
-
-            # One access allowed for any group
-            field_access_wo_group, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': None,
-                        'perm_write': True,
-                        }])
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # One access disallowed for any group
-            self.field_access.write([field_access_wo_group], {
-                    'perm_write': False,
-                    })
-
-            self.test_access.write([test], {})
-            self.assertRaises(UserError, self.test_access.write, [test],
-                {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
+        pool = Pool()
+        FieldAccess = pool.get('ir.model.field.access')
+        TestAccess = pool.get('test.access')
+        Field = pool.get('ir.model.field')
+        Group = pool.get('res.group')
+        transaction = Transaction()
+
+        field1, = Field.search([
+                ('model.model', '=', 'test.access'),
+                ('name', '=', 'field1'),
+                ])
+        field2, = Field.search([
+                ('model.model', '=', 'test.access'),
+                ('name', '=', 'field2'),
+                ])
+
+        test, = TestAccess.create([{
                     'field1': 'ham',
                     'field2': 'spam',
-                    })
-
-            # Two access rules with one group allowed
-            group = self.group.search([('users', '=', USER)])[0]
-            field_access_w_group, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': group.id,
-                        'perm_write': True,
-                        }])
-
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
+                    }])
 
-            # Two access rules with both allowed
-            self.field_access.write([field_access_wo_group], {
-                    'perm_write': True,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # Two access rules with any group allowed
-            self.field_access.write([field_access_w_group], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # Two access rules with both disallowed
-            self.field_access.write([field_access_wo_group], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-            self.assertRaises(UserError, self.test_access.write, [test],
-                {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # One access disallowed for one group
-            self.field_access.delete([field_access_wo_group])
-            self.test_access.write([test], {})
-            self.assertRaises(UserError, self.test_access.write, [test],
-                {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'ham'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
+        # Without field access
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+
+        # With field access
 
-            # One access allowed for one group
-            self.field_access.write([field_access_w_group], {
+        # One access allowed for any group
+        field_access_wo_group, = FieldAccess.create([{
+                    'field': field1.id,
+                    'group': None,
                     'perm_write': True,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
+                    }])
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
 
-            # One access allowed for one other group
-            group, = self.group.create([{'name': 'Test'}])
-            self.field_access.write([field_access_w_group], {
+        # One access disallowed for any group
+        FieldAccess.write([field_access_wo_group], {
+                'perm_write': False,
+                })
+
+        TestAccess.write([test], {})
+        self.assertRaises(UserError, TestAccess.write, [test],
+            {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+        self.assertRaises(UserError, TestAccess.write,
+            [test], {'field2': 'spam'}, [test], {'field1': 'ham'})
+
+        # Two access rules with one group allowed
+        group = Group.search([('users', '=', transaction.user)])[0]
+        field_access_w_group, = FieldAccess.create([{
+                    'field': field1.id,
                     'group': group.id,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # One access disallowed for one other group
-            self.field_access.write([field_access_w_group], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # Two access rules on both fields allowed
-            self.field_access.delete([field_access_w_group])
-
-            field_access1, = self.field_access.create([{
-                        'field': field1.id,
-                        'group': None,
-                        'perm_write': True,
-                        }])
-            field_access2, = self.field_access.create([{
-                        'field': field2.id,
-                        'group': None,
-                        'perm_write': True,
-                        }])
-
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.test_access.write([test], {'field2': 'spam'})
-            self.test_access.write([test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # Two access rules on both fields one allowed and one disallowed
-            self.field_access.write([field_access2], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-            self.test_access.write([test], {'field1': 'ham'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field2': 'spam'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
-
-            # Two access rules on both fields disallowed
-            self.field_access.write([field_access1], {
-                    'perm_write': False,
-                    })
-            self.test_access.write([test], {})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field1': 'ham'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field2': 'spam'})
-            self.assertRaises(UserError, self.test_access.write, [test], {
-                    'field1': 'ham',
-                    'field2': 'spam',
-                    })
+                    'perm_write': True,
+                    }])
+
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
 
-            transaction.cursor.rollback()
-            self.field_access._get_access_cache.clear()
+        # Two access rules with both allowed
+        FieldAccess.write([field_access_wo_group], {
+                'perm_write': True,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # Two access rules with any group allowed
+        FieldAccess.write([field_access_w_group], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # Two access rules with both disallowed
+        FieldAccess.write([field_access_wo_group], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+        self.assertRaises(UserError, TestAccess.write, [test],
+            {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # One access disallowed for one group
+        FieldAccess.delete([field_access_wo_group])
+        TestAccess.write([test], {})
+        self.assertRaises(UserError, TestAccess.write, [test],
+            {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'ham'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # One access allowed for one group
+        FieldAccess.write([field_access_w_group], {
+                'perm_write': True,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # One access allowed for one other group
+        group, = Group.create([{'name': 'Test'}])
+        FieldAccess.write([field_access_w_group], {
+                'group': group.id,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # One access disallowed for one other group
+        FieldAccess.write([field_access_w_group], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # Two access rules on both fields allowed
+        FieldAccess.delete([field_access_w_group])
+
+        field_access1, = FieldAccess.create([{
+                    'field': field1.id,
+                    'group': None,
+                    'perm_write': True,
+                    }])
+        field_access2, = FieldAccess.create([{
+                    'field': field2.id,
+                    'group': None,
+                    'perm_write': True,
+                    }])
+
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        TestAccess.write([test], {'field2': 'spam'})
+        TestAccess.write([test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # Two access rules on both fields one allowed and one disallowed
+        FieldAccess.write([field_access2], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+        TestAccess.write([test], {'field1': 'ham'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field2': 'spam'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
+
+        # Two access rules on both fields disallowed
+        FieldAccess.write([field_access1], {
+                'perm_write': False,
+                })
+        TestAccess.write([test], {})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field2': 'spam'})
+        self.assertRaises(UserError, TestAccess.write, [test], {
+                'field1': 'ham',
+                'field2': 'spam',
+                })
 
 
 def suite():
diff --git a/trytond/tests/test_copy.py b/trytond/tests/test_copy.py
index ceb642c..9e8c55f 100644
--- a/trytond/tests/test_copy.py
+++ b/trytond/tests/test_copy.py
@@ -2,75 +2,77 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 import unittest
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
-from trytond.transaction import Transaction
+
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 
 
 class CopyTestCase(unittest.TestCase):
     'Test copy'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.one2many = POOL.get('test.copy.one2many')
-        self.one2many_target = POOL.get('test.copy.one2many.target')
-        self.one2many_reference = POOL.get('test.copy.one2many_reference')
-        self.one2many_reference_target = \
-            POOL.get('test.copy.one2many_reference.target')
-        self.many2many = POOL.get('test.copy.many2many')
-        self.many2many_target = POOL.get('test.copy.many2many.target')
-        self.many2many_reference = POOL.get('test.copy.many2many_reference')
-        self.many2many_reference_target = \
-            POOL.get('test.copy.many2many_reference.target')
 
-    def test0130one2many(self):
-        'Test one2many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT):
-            for One2many, Target in (
-                    (self.one2many, self.one2many_target),
-                    (self.one2many_reference, self.one2many_reference_target),
-                    ):
-                one2many = One2many(name='Test')
-                one2many.one2many = [
-                    Target(name='Target 1'),
-                    Target(name='Target 2'),
-                    ]
-                one2many.save()
+    @with_transaction()
+    def test_one2many(self):
+        'Test copy one2many'
+        pool = Pool()
+        One2many_ = pool.get('test.copy.one2many')
+        One2manyTarget = pool.get('test.copy.one2many.target')
+        One2manyReference = pool.get('test.copy.one2many_reference')
+        One2manyReferenceTarget = \
+            pool.get('test.copy.one2many_reference.target')
+
+        for One2many, Target in (
+                (One2many_, One2manyTarget),
+                (One2manyReference, One2manyReferenceTarget),
+                ):
+            one2many = One2many(name='Test')
+            one2many.one2many = [
+                Target(name='Target 1'),
+                Target(name='Target 2'),
+                ]
+            one2many.save()
+
+            one2many_copy, = One2many.copy([one2many])
 
-                one2many_copy, = One2many.copy([one2many])
+            self.assertNotEqual(one2many, one2many_copy)
+            self.assertEqual(len(one2many.one2many),
+                len(one2many_copy.one2many))
+            self.assertNotEqual(one2many.one2many, one2many_copy.one2many)
+            self.assertEqual([x.name for x in one2many.one2many],
+                [x.name for x in one2many_copy.one2many])
 
-                self.assertNotEqual(one2many, one2many_copy)
-                self.assertEqual(len(one2many.one2many),
-                    len(one2many_copy.one2many))
-                self.assertNotEqual(one2many.one2many, one2many_copy.one2many)
-                self.assertEqual([x.name for x in one2many.one2many],
-                    [x.name for x in one2many_copy.one2many])
+    @with_transaction()
+    def test_many2many(self):
+        'Test copy many2many'
+        pool = Pool()
+        Many2many_ = pool.get('test.copy.many2many')
+        Many2manyTarget = pool.get('test.copy.many2many.target')
+        Many2manyReference = pool.get('test.copy.many2many_reference')
+        Many2manyReferenceTarget = \
+            pool.get('test.copy.many2many_reference.target')
 
-    def test0140many2many(self):
-        'Test many2many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT):
-            for Many2many, Target in (
-                    (self.many2many, self.many2many_target),
-                    (self.many2many_reference,
-                        self.many2many_reference_target),
-                    ):
-                many2many = Many2many(name='Test')
-                many2many.many2many = [
-                    Target(name='Target 1'),
-                    Target(name='Target 2'),
-                    ]
-                many2many.save()
+        for Many2many, Target in (
+                (Many2many_, Many2manyTarget),
+                (Many2manyReference, Many2manyReferenceTarget),
+                ):
+            many2many = Many2many(name='Test')
+            many2many.many2many = [
+                Target(name='Target 1'),
+                Target(name='Target 2'),
+                ]
+            many2many.save()
 
-                many2many_copy, = Many2many.copy([many2many])
+            many2many_copy, = Many2many.copy([many2many])
 
-                self.assertNotEqual(many2many, many2many_copy)
-                self.assertEqual(len(many2many.many2many),
-                    len(many2many_copy.many2many))
-                self.assertEqual(many2many.many2many, many2many_copy.many2many)
-                self.assertEqual([x.name for x in many2many.many2many],
-                    [x.name for x in many2many_copy.many2many])
+            self.assertNotEqual(many2many, many2many_copy)
+            self.assertEqual(len(many2many.many2many),
+                len(many2many_copy.many2many))
+            self.assertEqual(many2many.many2many, many2many_copy.many2many)
+            self.assertEqual([x.name for x in many2many.many2many],
+                [x.name for x in many2many_copy.many2many])
 
 
 def suite():
diff --git a/trytond/tests/test_exportdata.py b/trytond/tests/test_exportdata.py
index d95921c..6ae8bb1 100644
--- a/trytond/tests/test_exportdata.py
+++ b/trytond/tests/test_exportdata.py
@@ -12,352 +12,353 @@ except ImportError:
 import unittest
 from decimal import Decimal
 import datetime
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
-from trytond.transaction import Transaction
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 
 
 class ExportDataTestCase(unittest.TestCase):
     'Test export_data'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.export_data = POOL.get('test.export_data')
-        self.export_data_target = POOL.get('test.export_data.target')
-        self.export_data_relation = POOL.get('test.export_data.relation')
-
-    def test0010boolean(self):
-        'Test boolean'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'boolean': True,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['boolean']), [[True]])
-
-            export2, = self.export_data.create([{
-                        'boolean': False,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['boolean']),
-                [[False]])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2],
-                    ['boolean']),
-                [[True], [False]])
-
-            transaction.cursor.rollback()
-
-    def test0020integer(self):
-        'Test integer'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'integer': 2,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['integer']), [[2]])
-
-            export2, = self.export_data.create([{
-                        'integer': 0,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['integer']), [[0]])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['integer']),
-                [[2], [0]])
-
-            transaction.cursor.rollback()
-
-    def test0030float(self):
-        'Test float'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'float': 1.1,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['float']), [[1.1]])
-
-            export2, = self.export_data.create([{
-                        'float': 0,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['float']), [[0]])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['float']),
-                [[1.1], [0]])
-
-            transaction.cursor.rollback()
-
-    def test0040numeric(self):
-        'Test numeric'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'numeric': Decimal('1.1'),
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['numeric']),
-                [[Decimal('1.1')]])
-
-            export2, = self.export_data.create([{
-                        'numeric': Decimal('0'),
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['numeric']),
-                [[Decimal('0')]])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['numeric']),
-                [[Decimal('1.1')], [Decimal('0')]])
-
-            transaction.cursor.rollback()
-
-    def test0050char(self):
-        'Test char'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'char': 'test',
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['char']), [['test']])
-
-            export2, = self.export_data.create([{
-                        'char': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['char']), [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['char']),
-                [['test'], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0060text(self):
-        'Test text'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'text': 'test',
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['text']), [['test']])
-
-            export2, = self.export_data.create([{
-                        'text': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['text']), [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['text']),
-                [['test'], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0080date(self):
-        'Test date'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'date': datetime.date(2010, 1, 1),
-                        }])
-            self.assert_(self.export_data.export_data([export1],
-                ['date']) == [[datetime.date(2010, 1, 1)]])
-
-            export2, = self.export_data.create([{
-                        'date': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['date']), [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['date']),
-                [[datetime.date(2010, 1, 1)], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0090datetime(self):
-        'Test datetime'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'datetime': datetime.datetime(2010, 1, 1, 12, 0, 0),
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['datetime']),
-                [[datetime.datetime(2010, 1, 1, 12, 0, 0)]])
-
-            export2, = self.export_data.create([{
-                        'datetime': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['datetime']),
-                [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['datetime']),
-                [[datetime.datetime(2010, 1, 1, 12, 0, 0)], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0100selection(self):
-        'Test selection'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{
-                        'selection': 'select1',
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['selection',
-                        'selection.translated']),
-                [['select1', 'Select 1']])
-
-            export2, = self.export_data.create([{
-                        'selection': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['selection']), [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2],
-                    ['selection']),
-                [['select1'], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0110many2one(self):
-        'Test many2one'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            target, = self.export_data_target.create([{
-                        'name': 'Target Test',
-                        }])
-            export1, = self.export_data.create([{
-                        'many2one': target.id,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['many2one/name']),
-                [['Target Test']])
-
-            export2, = self.export_data.create([{
-                    'many2one': None,
+
+    @with_transaction()
+    def test_boolean(self):
+        'Test export_data boolean'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'boolean': True,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['boolean']), [[True]])
+
+        export2, = ExportData.create([{
+                    'boolean': False,
                     }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['many2one/name']),
-                [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2],
-                    ['many2one/name']),
-                [['Target Test'], ['']])
-
-            transaction.cursor.rollback()
-
-    def test0120many2many(self):
-        'Test many2many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            target1, = self.export_data_target.create([{
-                        'name': 'Target 1',
-                        }])
-            export1, = self.export_data.create([{
-                        'many2many': [('add', [target1])],
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['many2many/name']),
-                [['Target 1']])
-
-            target2, = self.export_data_target.create([{
-                        'name': 'Target 2',
-                        }])
-            self.export_data.write([export1], {
-                    'many2many': [('add', [target1.id, target2.id])],
-                    })
-            self.assertEqual(
-                self.export_data.export_data([export1], ['id',
-                        'many2many/name']),
-                [[export1.id, 'Target 1'], ['', 'Target 2']])
-
-            export2, = self.export_data.create([{
-                        'many2many': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['many2many/name']),
-                [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2],
-                    ['id', 'many2many/name']),
-                [[export1.id, 'Target 1'], ['', 'Target 2'], [export2.id, '']])
-
-            transaction.cursor.rollback()
-
-    def test0130one2many(self):
-        'Test one2many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            export1, = self.export_data.create([{}])
-            self.export_data_target.create([{
-                        'name': 'Target 1',
-                        'one2many': export1.id,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['one2many/name']),
-                [['Target 1']])
-
-            self.export_data_target.create([{
-                        'name': 'Target 2',
-                        'one2many': export1.id,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1],
-                    ['id', 'one2many/name']),
-                [[export1.id, 'Target 1'], ['', 'Target 2']])
-
-            export2, = self.export_data.create([{}])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['one2many/name']),
-                [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2], ['id',
-                        'one2many/name']),
-                [[export1.id, 'Target 1'], ['', 'Target 2'], [export2.id, '']])
-
-            transaction.cursor.rollback()
-
-    def test0140reference(self):
-        'Test reference'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            target1, = self.export_data_target.create([{}])
-            export1, = self.export_data.create([{
-                        'reference': str(target1),
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export1], ['reference']),
-                [[str(target1)]])
-
-            export2, = self.export_data.create([{
-                        'reference': None,
-                        }])
-            self.assertEqual(
-                self.export_data.export_data([export2], ['reference']), [['']])
-
-            self.assertEqual(
-                self.export_data.export_data([export1, export2],
-                    ['reference']),
-                [[str(target1)], ['']])
-
-            transaction.cursor.rollback()
+        self.assertEqual(
+            ExportData.export_data([export2], ['boolean']),
+            [[False]])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2],
+                ['boolean']),
+            [[True], [False]])
+
+    @with_transaction()
+    def test_integer(self):
+        'Test export_data integer'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'integer': 2,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['integer']), [[2]])
+
+        export2, = ExportData.create([{
+                    'integer': 0,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['integer']), [[0]])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['integer']),
+            [[2], [0]])
+
+    @with_transaction()
+    def test_float(self):
+        'Test export_data float'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'float': 1.1,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['float']), [[1.1]])
+
+        export2, = ExportData.create([{
+                    'float': 0,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['float']), [[0]])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['float']),
+            [[1.1], [0]])
+
+    @with_transaction()
+    def test_numeric(self):
+        'Test export_data numeric'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'numeric': Decimal('1.1'),
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['numeric']),
+            [[Decimal('1.1')]])
+
+        export2, = ExportData.create([{
+                    'numeric': Decimal('0'),
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['numeric']),
+            [[Decimal('0')]])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['numeric']),
+            [[Decimal('1.1')], [Decimal('0')]])
+
+    @with_transaction()
+    def test_char(self):
+        'Test export_data char'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'char': 'test',
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['char']), [['test']])
+
+        export2, = ExportData.create([{
+                    'char': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['char']), [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['char']),
+            [['test'], ['']])
+
+    @with_transaction()
+    def test_text(self):
+        'Test export_data text'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'text': 'test',
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['text']), [['test']])
+
+        export2, = ExportData.create([{
+                    'text': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['text']), [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['text']),
+            [['test'], ['']])
+
+    @with_transaction()
+    def test_date(self):
+        'Test export_data date'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'date': datetime.date(2010, 1, 1),
+                    }])
+        self.assert_(ExportData.export_data([export1],
+            ['date']) == [[datetime.date(2010, 1, 1)]])
+
+        export2, = ExportData.create([{
+                    'date': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['date']), [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['date']),
+            [[datetime.date(2010, 1, 1)], ['']])
+
+    @with_transaction()
+    def test_datetime(self):
+        'Test export_data datetime'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'datetime': datetime.datetime(2010, 1, 1, 12, 0, 0),
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['datetime']),
+            [[datetime.datetime(2010, 1, 1, 12, 0, 0)]])
+
+        export2, = ExportData.create([{
+                    'datetime': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['datetime']),
+            [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['datetime']),
+            [[datetime.datetime(2010, 1, 1, 12, 0, 0)], ['']])
+
+    @with_transaction()
+    def test_selection(self):
+        'Test export_data selection'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+
+        export1, = ExportData.create([{
+                    'selection': 'select1',
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['selection',
+                    'selection.translated']),
+            [['select1', 'Select 1']])
+
+        export2, = ExportData.create([{
+                    'selection': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['selection']), [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2],
+                ['selection']),
+            [['select1'], ['']])
+
+    @with_transaction()
+    def test_many2one(self):
+        'Test export_data many2one'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+        ExportDataTarget = pool.get('test.export_data.target')
+
+        target, = ExportDataTarget.create([{
+                    'name': 'Target Test',
+                    }])
+        export1, = ExportData.create([{
+                    'many2one': target.id,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['many2one/name']),
+            [['Target Test']])
+
+        export2, = ExportData.create([{
+                'many2one': None,
+                }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['many2one/name']),
+            [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2],
+                ['many2one/name']),
+            [['Target Test'], ['']])
+
+    @with_transaction()
+    def test_many2many(self):
+        'Test export_data many2many'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+        ExportDataTarget = pool.get('test.export_data.target')
+
+        target1, = ExportDataTarget.create([{
+                    'name': 'Target 1',
+                    }])
+        export1, = ExportData.create([{
+                    'many2many': [('add', [target1])],
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['many2many/name']),
+            [['Target 1']])
+
+        target2, = ExportDataTarget.create([{
+                    'name': 'Target 2',
+                    }])
+        ExportData.write([export1], {
+                'many2many': [('add', [target1.id, target2.id])],
+                })
+        self.assertEqual(
+            ExportData.export_data([export1], ['id',
+                    'many2many/name']),
+            [[export1.id, 'Target 1'], ['', 'Target 2']])
+
+        export2, = ExportData.create([{
+                    'many2many': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['many2many/name']),
+            [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2],
+                ['id', 'many2many/name']),
+            [[export1.id, 'Target 1'], ['', 'Target 2'], [export2.id, '']])
+
+    @with_transaction()
+    def test_one2many(self):
+        'Test export_data one2many'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+        ExportDataTarget = pool.get('test.export_data.target')
+
+        export1, = ExportData.create([{}])
+        ExportDataTarget.create([{
+                    'name': 'Target 1',
+                    'one2many': export1.id,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['one2many/name']),
+            [['Target 1']])
+
+        ExportDataTarget.create([{
+                    'name': 'Target 2',
+                    'one2many': export1.id,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1],
+                ['id', 'one2many/name']),
+            [[export1.id, 'Target 1'], ['', 'Target 2']])
+
+        export2, = ExportData.create([{}])
+        self.assertEqual(
+            ExportData.export_data([export2], ['one2many/name']),
+            [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2], ['id',
+                    'one2many/name']),
+            [[export1.id, 'Target 1'], ['', 'Target 2'], [export2.id, '']])
+
+    @with_transaction()
+    def test_reference(self):
+        'Test export_data reference'
+        pool = Pool()
+        ExportData = pool.get('test.export_data')
+        ExportDataTarget = pool.get('test.export_data.target')
+
+        target1, = ExportDataTarget.create([{}])
+        export1, = ExportData.create([{
+                    'reference': str(target1),
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export1], ['reference']),
+            [[str(target1)]])
+
+        export2, = ExportData.create([{
+                    'reference': None,
+                    }])
+        self.assertEqual(
+            ExportData.export_data([export2], ['reference']), [['']])
+
+        self.assertEqual(
+            ExportData.export_data([export1, export2],
+                ['reference']),
+            [[str(target1)], ['']])
 
 
 def suite():
diff --git a/trytond/tests/test_field_context.py b/trytond/tests/test_field_context.py
index 99a9cbc..6a71a05 100644
--- a/trytond/tests/test_field_context.py
+++ b/trytond/tests/test_field_context.py
@@ -3,30 +3,31 @@
 
 import unittest
 
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
-from trytond.transaction import Transaction
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 
 
 class FieldContextTestCase(unittest.TestCase):
     "Test context on field"
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
+    @with_transaction()
     def test_context(self):
-        Parent = POOL.get('test.field_context.parent')
-        Child = POOL.get('test.field_context.child')
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            child = Child()
-            child.save()
-            parent = Parent(name='foo', child=child)
-            parent.save()
-            self.assertEqual(parent.child._context['name'], 'foo')
-
-            parent.name = 'bar'
-            parent.save()
-            self.assertEqual(parent.child._context['name'], 'bar')
+        pool = Pool()
+        Parent = pool.get('test.field_context.parent')
+        Child = pool.get('test.field_context.child')
+        child = Child()
+        child.save()
+        parent = Parent(name='foo', child=child)
+        parent.save()
+        self.assertEqual(parent.child._context['name'], 'foo')
+
+        parent.name = 'bar'
+        parent.save()
+        self.assertEqual(parent.child._context['name'], 'bar')
 
 
 def suite():
diff --git a/trytond/tests/test_fields.py b/trytond/tests/test_fields.py
index c6c64cf..10b0b78 100644
--- a/trytond/tests/test_fields.py
+++ b/trytond/tests/test_fields.py
@@ -12,3499 +12,3626 @@ except ImportError:
 import unittest
 import datetime
 from decimal import Decimal
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
 from trytond.exceptions import UserError
 from trytond.model import fields
+from trytond.pool import Pool
 
 
 class FieldsTestCase(unittest.TestCase):
     'Test Fields'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.boolean = POOL.get('test.boolean')
-        self.boolean_default = POOL.get('test.boolean_default')
-
-        self.integer = POOL.get('test.integer')
-        self.integer_default = POOL.get('test.integer_default')
-        self.integer_required = POOL.get('test.integer_required')
-        self.integer_domain = POOL.get('test.integer_domain')
-
-        self.float = POOL.get('test.float')
-        self.float_default = POOL.get('test.float_default')
-        self.float_required = POOL.get('test.float_required')
-        self.float_digits = POOL.get('test.float_digits')
-
-        self.numeric = POOL.get('test.numeric')
-        self.numeric_default = POOL.get('test.numeric_default')
-        self.numeric_required = POOL.get('test.numeric_required')
-        self.numeric_digits = POOL.get('test.numeric_digits')
-
-        self.char = POOL.get('test.char')
-        self.char_default = POOL.get('test.char_default')
-        self.char_required = POOL.get('test.char_required')
-        self.char_size = POOL.get('test.char_size')
-        self.char_translate = POOL.get('test.char_translate')
-
-        self.text = POOL.get('test.text')
-        self.text_default = POOL.get('test.text_default')
-        self.text_required = POOL.get('test.text_required')
-        self.text_size = POOL.get('test.text_size')
-        self.text_translate = POOL.get('test.text_translate')
-
-        self.date = POOL.get('test.date')
-        self.date_default = POOL.get('test.date_default')
-        self.date_required = POOL.get('test.date_required')
-
-        self.datetime = POOL.get('test.datetime')
-        self.datetime_default = POOL.get('test.datetime_default')
-        self.datetime_required = POOL.get('test.datetime_required')
-        self.datetime_format = POOL.get('test.datetime_format')
-
-        self.time = POOL.get('test.time')
-        self.time_default = POOL.get('test.time_default')
-        self.time_required = POOL.get('test.time_required')
-        self.time_format = POOL.get('test.time_format')
-
-        self.timedelta = POOL.get('test.timedelta')
-        self.timedelta_default = POOL.get('test.timedelta_default')
-        self.timedelta_required = POOL.get('test.timedelta_required')
-
-        self.one2one = POOL.get('test.one2one')
-        self.one2one_target = POOL.get('test.one2one.target')
-        self.one2one_required = POOL.get('test.one2one_required')
-        self.one2one_domain = POOL.get('test.one2one_domain')
-
-        self.one2many = POOL.get('test.one2many')
-        self.one2many_target = POOL.get('test.one2many.target')
-        self.one2many_required = POOL.get('test.one2many_required')
-        self.one2many_reference = POOL.get('test.one2many_reference')
-        self.one2many_reference_target = POOL.get(
-            'test.one2many_reference.target')
-        self.one2many_size = POOL.get('test.one2many_size')
-        self.one2many_size_pyson = POOL.get('test.one2many_size_pyson')
-
-        self.many2many = POOL.get('test.many2many')
-        self.many2many_target = POOL.get('test.many2many.target')
-        self.many2many_required = POOL.get('test.many2many_required')
-        self.many2many_reference = POOL.get('test.many2many_reference')
-        self.many2many_reference_target = POOL.get(
-            'test.many2many_reference.target')
-        self.many2many_size = POOL.get('test.many2many_size')
-        self.many2many_size_target = POOL.get('test.many2many_size.target')
-
-        self.reference = POOL.get('test.reference')
-        self.reference_target = POOL.get('test.reference.target')
-        self.reference_required = POOL.get('test.reference_required')
-
-        self.property_ = POOL.get('test.property')
-        self.ir_property = POOL.get('ir.property')
-        self.model_field = POOL.get('ir.model.field')
-
-        self.selection = POOL.get('test.selection')
-        self.selection_required = POOL.get('test.selection_required')
-
-        self.dict_ = POOL.get('test.dict')
-        self.dict_schema = POOL.get('test.dict.schema')
-        self.dict_default = POOL.get('test.dict_default')
-        self.dict_required = POOL.get('test.dict_required')
-
-        self.binary = POOL.get('test.binary')
-        self.binary_default = POOL.get('test.binary_default')
-        self.binary_required = POOL.get('test.binary_required')
-
-        self.m2o_domain_validation = POOL.get('test.many2one_domainvalidation')
-        self.m2o_orderby = POOL.get('test.many2one_orderby')
-        self.m2o_target = POOL.get('test.many2one_target')
-        self.m2o_search = POOL.get('test.many2one_search')
-
-    def test0010boolean(self):
+
+    @with_transaction()
+    def test_boolean(self):
         'Test Boolean'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            boolean1, = self.boolean.create([{
-                        'boolean': True,
-                        }])
-            self.assert_(boolean1)
-            self.assertEqual(boolean1.boolean, True)
+        pool = Pool()
+        Boolean = pool.get('test.boolean')
+        BooleanDefault = pool.get('test.boolean_default')
 
-            booleans = self.boolean.search([
-                    ('boolean', '=', True),
-                    ])
-            self.assertEqual(booleans, [boolean1])
+        boolean1, = Boolean.create([{
+                    'boolean': True,
+                    }])
+        self.assert_(boolean1)
+        self.assertEqual(boolean1.boolean, True)
+
+        booleans = Boolean.search([
+                ('boolean', '=', True),
+                ])
+        self.assertEqual(booleans, [boolean1])
+
+        booleans = Boolean.search([
+                ('boolean', '!=', True),
+                ])
+        self.assertEqual(booleans, [])
+
+        booleans = Boolean.search([
+                ('boolean', 'in', [True]),
+                ])
+        self.assertEqual(booleans, [boolean1])
+
+        booleans = Boolean.search([
+                ('boolean', 'in', [False]),
+                ])
+        self.assertEqual(booleans, [])
+
+        booleans = Boolean.search([
+                ('boolean', 'not in', [True]),
+                ])
+        self.assertEqual(booleans, [])
+
+        booleans = Boolean.search([
+                ('boolean', 'not in', [False]),
+                ])
+        self.assertEqual(booleans, [boolean1])
+
+        boolean2, = Boolean.create([{
+                    'boolean': False,
+                    }])
+        self.assert_(boolean2)
+        self.assertEqual(boolean2.boolean, False)
+
+        booleans = Boolean.search([
+                ('boolean', '=', False),
+                ])
+        self.assertEqual(booleans, [boolean2])
+
+        booleans = Boolean.search([
+                ('boolean', 'in', [True, False]),
+                ])
+        self.assertEqual(booleans, [boolean1, boolean2])
+
+        booleans = Boolean.search([
+                ('boolean', 'not in', [True, False]),
+                ])
+        self.assertEqual(booleans, [])
+
+        boolean3, = Boolean.create([{}])
+        self.assert_(boolean3)
+        self.assertEqual(boolean3.boolean, False)
+
+        # Test search with NULL value
+        boolean4, = Boolean.create([{
+                    'boolean': None,
+                    }])
+        self.assert_(boolean4)
+
+        booleans = Boolean.search([
+                ('boolean', '=', False),
+                ])
+        self.assertEqual(booleans,
+            [boolean2, boolean3, boolean4])
+
+        booleans = Boolean.search([
+                ('boolean', '!=', False),
+                ])
+        self.assertEqual(booleans, [boolean1])
+
+        boolean4, = BooleanDefault.create([{}])
+        self.assert_(boolean4)
+        self.assertTrue(boolean4.boolean)
+
+        Boolean.write([boolean1], {
+                'boolean': False,
+                })
+        self.assertEqual(boolean1.boolean, False)
+
+        Boolean.write([boolean2], {
+                'boolean': True,
+                })
+        self.assertEqual(boolean2.boolean, True)
+
+    @with_transaction()
+    def test_integer(self):
+        'Test Integer'
+        pool = Pool()
+        Integer = pool.get('test.integer')
+        IntegerDefault = pool.get('test.integer_default')
+        IntegerRequired = pool.get('test.integer_required')
+        transaction = Transaction()
 
-            booleans = self.boolean.search([
-                    ('boolean', '!=', True),
-                    ])
-            self.assertEqual(booleans, [])
+        integer1, = Integer.create([{
+                    'integer': 1,
+                    }])
+        self.assert_(integer1)
+        self.assertEqual(integer1.integer, 1)
+
+        integers = Integer.search([
+                ('integer', '=', 1),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '=', 0),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '!=', 1),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '!=', 0),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', 'in', [1]),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', 'in', [0]),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', 'in', []),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', 'not in', [1]),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', 'not in', [0]),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', 'not in', []),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '<', 5),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '<', -5),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '<', 1),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '<=', 5),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '<=', -5),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '<=', 1),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '>', 5),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '>', -5),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '>', 1),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '>=', 5),
+                ])
+        self.assertEqual(integers, [])
+
+        integers = Integer.search([
+                ('integer', '>=', -5),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integers = Integer.search([
+                ('integer', '>=', 1),
+                ])
+        self.assertEqual(integers, [integer1])
+
+        integer2, = Integer.create([{
+                    'integer': 0,
+                    }])
+        self.assert_(integer2)
+        self.assertEqual(integer2.integer, 0)
+
+        integers = Integer.search([
+                ('integer', '=', 0),
+                ])
+        self.assertEqual(integers, [integer2])
+
+        integers = Integer.search([
+                ('integer', 'in', [0, 1]),
+                ])
+        self.assertEqual(integers, [integer1, integer2])
+
+        integers = Integer.search([
+                ('integer', 'not in', [0, 1]),
+                ])
+        self.assertEqual(integers, [])
+
+        integer3, = Integer.create([{}])
+        self.assert_(integer3)
+        self.assertEqual(integer3.integer, None)
+
+        integer4, = IntegerDefault.create([{}])
+        self.assert_(integer4)
+        self.assertEqual(integer4.integer, 5)
+
+        Integer.write([integer1], {
+                'integer': 0,
+                })
+        self.assertEqual(integer1.integer, 0)
+
+        Integer.write([integer2], {
+                'integer': 1,
+                })
+        self.assertEqual(integer2.integer, 1)
+
+        self.assertRaises(Exception, Integer.create, [{
+                    'integer': 'test',
+                    }])
 
-            booleans = self.boolean.search([
-                    ('boolean', 'in', [True]),
-                    ])
-            self.assertEqual(booleans, [boolean1])
+        self.assertRaises(Exception, Integer.write, [integer1], {
+                'integer': 'test',
+                })
 
-            booleans = self.boolean.search([
-                    ('boolean', 'in', [False]),
-                    ])
-            self.assertEqual(booleans, [])
+        # We should catch UserError but mysql does not raise an
+        # IntegrityError but an OperationalError
+        self.assertRaises(Exception, IntegerRequired.create, [{}])
+        transaction.rollback()
 
-            booleans = self.boolean.search([
-                    ('boolean', 'not in', [True]),
-                    ])
-            self.assertEqual(booleans, [])
+        integer5, = IntegerRequired.create([{
+                    'integer': 0,
+                    }])
+        self.assert_(integer5)
+        self.assertEqual(integer5.integer, 0)
 
-            booleans = self.boolean.search([
-                    ('boolean', 'not in', [False]),
-                    ])
-            self.assertEqual(booleans, [boolean1])
+        transaction.rollback()
 
-            boolean2, = self.boolean.create([{
-                        'boolean': False,
-                        }])
-            self.assert_(boolean2)
-            self.assertEqual(boolean2.boolean, False)
+    @with_transaction()
+    def test_integer_with_domain(self):
+        'Test Integer with domain'
+        pool = Pool()
+        IntegerDomain = pool.get('test.integer_domain')
+        IntegerDomain.create([{
+                    'integer': 100,
+                    }])
+        self.assertRaises(UserError, IntegerDomain.create, [{
+                    'integer': 10,
+                    }])
 
-            booleans = self.boolean.search([
-                    ('boolean', '=', False),
-                    ])
-            self.assertEqual(booleans, [boolean2])
+    @with_transaction()
+    def test_float(self):
+        'Test Float'
+        pool = Pool()
+        Float = pool.get('test.float')
+        FloatDefault = pool.get('test.float_default')
+        FloatRequired = pool.get('test.float_required')
+        FloatDigits = pool.get('test.float_digits')
+        transaction = Transaction()
+
+        float1, = Float.create([{
+                    'float': 1.1,
+                    }])
+        self.assert_(float1)
+        self.assertEqual(float1.float, 1.1)
+
+        floats = Float.search([
+                ('float', '=', 1.1),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '=', 0),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '!=', 1.1),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '!=', 0),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', 'in', [1.1]),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', 'in', [0]),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', 'in', []),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', 'not in', [1.1]),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', 'not in', [0]),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', 'not in', []),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '<', 5),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '<', -5),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '<', 1.1),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '<=', 5),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '<=', -5),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '<=', 1.1),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '>', 5),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '>', -5),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '>', 1.1),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '>=', 5),
+                ])
+        self.assertEqual(floats, [])
+
+        floats = Float.search([
+                ('float', '>=', -5),
+                ])
+        self.assertEqual(floats, [float1])
+
+        floats = Float.search([
+                ('float', '>=', 1.1),
+                ])
+        self.assertEqual(floats, [float1])
+
+        float2, = Float.create([{
+                    'float': 0,
+                    }])
+        self.assert_(float2)
+        self.assertEqual(float2.float, 0)
+
+        floats = Float.search([
+                ('float', '=', 0),
+                ])
+        self.assertEqual(floats, [float2])
+
+        floats = Float.search([
+                ('float', 'in', [0, 1.1]),
+                ])
+        self.assertEqual(floats, [float1, float2])
+
+        floats = Float.search([
+                ('float', 'not in', [0, 1.1]),
+                ])
+        self.assertEqual(floats, [])
+
+        float3, = Float.create([{}])
+        self.assert_(float3)
+        self.assertEqual(float3.float, None)
+
+        float4, = FloatDefault.create([{}])
+        self.assert_(float4)
+        self.assertEqual(float4.float, 5.5)
+
+        Float.write([float1], {
+                'float': 0,
+                })
+        self.assertEqual(float1.float, 0)
+
+        Float.write([float2], {
+                'float': 1.1,
+                })
+        self.assertEqual(float2.float, 1.1)
+
+        self.assertRaises(Exception, Float.create, [{
+                    'float': 'test',
+                    }])
 
-            booleans = self.boolean.search([
-                    ('boolean', 'in', [True, False]),
-                    ])
-            self.assertEqual(booleans, [boolean1, boolean2])
+        self.assertRaises(Exception, Float.write, [float1], {
+                'float': 'test',
+                })
 
-            booleans = self.boolean.search([
-                    ('boolean', 'not in', [True, False]),
-                    ])
-            self.assertEqual(booleans, [])
+        self.assertRaises(UserError, FloatRequired.create, [{}])
+        transaction.rollback()
 
-            boolean3, = self.boolean.create([{}])
-            self.assert_(boolean3)
-            self.assertEqual(boolean3.boolean, False)
+        float5, = FloatRequired.create([{
+                    'float': 0.0,
+                    }])
+        self.assertEqual(float5.float, 0.0)
 
-            # Test search with NULL value
-            boolean4, = self.boolean.create([{
-                        'boolean': None,
-                        }])
-            self.assert_(boolean4)
+        float6, = FloatDigits.create([{
+                    'digits': 1,
+                    'float': 1.1,
+                    }])
+        self.assert_(float6)
 
-            booleans = self.boolean.search([
-                    ('boolean', '=', False),
-                    ])
-            self.assertEqual(booleans,
-                [boolean2, boolean3, boolean4])
+        self.assertRaises(UserError, FloatDigits.create, [{
+                    'digits': 1,
+                    'float': 1.11,
+                    }])
 
-            booleans = self.boolean.search([
-                    ('boolean', '!=', False),
-                    ])
-            self.assertEqual(booleans, [boolean1])
+        self.assertRaises(UserError, FloatDigits.write,
+            [float6], {
+                'float': 1.11,
+                })
 
-            boolean4, = self.boolean_default.create([{}])
-            self.assert_(boolean4)
-            self.assertTrue(boolean4.boolean)
+        self.assertRaises(UserError, FloatDigits.write,
+            [float6], {
+                'digits': 0,
+                })
 
-            self.boolean.write([boolean1], {
-                    'boolean': False,
-                    })
-            self.assertEqual(boolean1.boolean, False)
+        float7, = Float.create([{
+                    'float': 0.123456789012345,
+                    }])
+        self.assertEqual(float7.float, 0.123456789012345)
 
-            self.boolean.write([boolean2], {
-                    'boolean': True,
-                    })
-            self.assertEqual(boolean2.boolean, True)
+    @with_transaction()
+    def test_float_search_none(self):
+        'Test float search with None'
+        pool = Pool()
+        Float = pool.get('test.float')
 
-            transaction.cursor.rollback()
+        float_none, float0, float1 = Float.create([{
+                    'float': None,
+                    }, {
+                    'float': 0,
+                    }, {
+                    'float': 1,
+                    }])
+        self.assertEqual([float_none], Float.search([
+                    ('float', '=', None),
+                    ]))
+        self.assertEqual([float0], Float.search([
+                    ('float', '=', 0),
+                    ]))
+        self.assertEqual([float1], Float.search([
+                    ('float', '>', 0),
+                    ]))
+
+        self.assertEqual([float0, float1], Float.search([
+                    ('float', '!=', None),
+                    ]))
+        self.assertEqual([float1], Float.search([
+                    ('float', '!=', 0),
+                    ]))
+        self.assertEqual([float0], Float.search([
+                    ('float', '<', 1),
+                    ]))
+
+        self.assertEqual([float_none, float1], Float.search([
+                    'OR',
+                    ('float', '>', 0),
+                    ('float', '=', None),
+                    ]))
+
+    @with_transaction()
+    def test_numeric(self):
+        'Test Numeric'
+        pool = Pool()
+        Numeric = pool.get('test.numeric')
+        NumericDefault = pool.get('test.numeric_default')
+        NumericRequired = pool.get('test.numeric_required')
+        NumericDigits = pool.get('test.numeric_digits')
+        transaction = Transaction()
+
+        numeric1, = Numeric.create([{
+                    'numeric': Decimal('1.1'),
+                    }])
+        self.assert_(numeric1)
+        self.assertEqual(numeric1.numeric, Decimal('1.1'))
+
+        numerics = Numeric.search([
+                ('numeric', '=', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '=', Decimal('0')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '!=', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '!=', Decimal('0')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', 'in', [Decimal('1.1')]),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', 'in', [Decimal('0')]),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', 'in', []),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', 'not in', [Decimal('1.1')]),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', 'not in', [Decimal('0')]),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', 'not in', []),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '<', Decimal('5')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '<', Decimal('-5')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '<', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '<=', Decimal('5')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '<=', Decimal('-5')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '<=', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '>', Decimal('5')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '>', Decimal('-5')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '>', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '>=', Decimal('5')),
+                ])
+        self.assertEqual(numerics, [])
+
+        numerics = Numeric.search([
+                ('numeric', '>=', Decimal('-5')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numerics = Numeric.search([
+                ('numeric', '>=', Decimal('1.1')),
+                ])
+        self.assertEqual(numerics, [numeric1])
+
+        numeric2, = Numeric.create([{
+                    'numeric': Decimal('0'),
+                    }])
+        self.assert_(numeric2)
+        self.assertEqual(numeric2.numeric, Decimal('0'))
+
+        numerics = Numeric.search([
+                ('numeric', '=', Decimal('0')),
+                ])
+        self.assertEqual(numerics, [numeric2])
+
+        numerics = Numeric.search([
+                ('numeric', 'in', [Decimal('0'), Decimal('1.1')]),
+                ])
+        self.assertEqual(numerics, [numeric1, numeric2])
+
+        numerics = Numeric.search([
+                ('numeric', 'not in', [Decimal('0'), Decimal('1.1')]),
+                ])
+        self.assertEqual(numerics, [])
+
+        numeric3, = Numeric.create([{}])
+        self.assert_(numeric3)
+        self.assertEqual(numeric3.numeric, None)
+
+        numeric4, = NumericDefault.create([{}])
+        self.assert_(numeric4)
+        self.assertEqual(numeric4.numeric, Decimal('5.5'))
+
+        Numeric.write([numeric1], {
+                'numeric': Decimal('0'),
+                })
+        self.assertEqual(numeric1.numeric, Decimal('0'))
+
+        Numeric.write([numeric2], {
+                'numeric': Decimal('1.1'),
+                })
+        self.assertEqual(numeric2.numeric, Decimal('1.1'))
+
+        self.assertRaises(Exception, Numeric.create, [{
+                    'numeric': 'test',
+                    }])
 
-    def test0020integer(self):
-        'Test Integer'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            integer1, = self.integer.create([{
-                        'integer': 1,
-                        }])
-            self.assert_(integer1)
-            self.assertEqual(integer1.integer, 1)
+        self.assertRaises(Exception, Numeric.write, [numeric1], {
+                'numeric': 'test',
+                })
 
-            integers = self.integer.search([
-                    ('integer', '=', 1),
-                    ])
-            self.assertEqual(integers, [integer1])
+        self.assertRaises(UserError, NumericRequired.create, [{}])
+        transaction.rollback()
 
-            integers = self.integer.search([
-                    ('integer', '=', 0),
-                    ])
-            self.assertEqual(integers, [])
+        numeric5, = NumericRequired.create([{
+                'numeric': Decimal(0),
+                }])
+        self.assertEqual(numeric5.numeric, 0)
 
-            integers = self.integer.search([
-                    ('integer', '!=', 1),
-                    ])
-            self.assertEqual(integers, [])
+        numeric6, = NumericDigits.create([{
+                    'digits': 1,
+                    'numeric': Decimal('1.1'),
+                    }])
+        self.assert_(numeric6)
 
-            integers = self.integer.search([
-                    ('integer', '!=', 0),
-                    ])
-            self.assertEqual(integers, [integer1])
+        self.assertRaises(UserError, NumericDigits.create, [{
+                    'digits': 1,
+                    'numeric': Decimal('1.11'),
+                    }])
 
-            integers = self.integer.search([
-                    ('integer', 'in', [1]),
-                    ])
-            self.assertEqual(integers, [integer1])
+        self.assertRaises(UserError, NumericDigits.write,
+            [numeric6], {
+                'numeric': Decimal('1.11'),
+                })
 
-            integers = self.integer.search([
-                    ('integer', 'in', [0]),
-                    ])
-            self.assertEqual(integers, [])
+        self.assertRaises(UserError, NumericDigits.write,
+            [numeric6], {
+                'numeric': Decimal('0.10000000000000001'),
+                })
 
-            integers = self.integer.search([
-                    ('integer', 'in', []),
-                    ])
-            self.assertEqual(integers, [])
+        self.assertRaises(UserError, NumericDigits.write,
+            [numeric6], {
+                'digits': 0,
+                })
 
-            integers = self.integer.search([
-                    ('integer', 'not in', [1]),
-                    ])
-            self.assertEqual(integers, [])
+        numeric7, = Numeric.create([{
+                    'numeric': Decimal('0.1234567890123456789'),
+                    }])
+        self.assertEqual(numeric7.numeric,
+            Decimal('0.1234567890123456789'))
 
-            integers = self.integer.search([
-                    ('integer', 'not in', [0]),
-                    ])
-            self.assertEqual(integers, [integer1])
+    @with_transaction()
+    def test_numeric_search_cast(self):
+        'Test numeric search cast'
+        pool = Pool()
+        Numeric = pool.get('test.numeric')
 
-            integers = self.integer.search([
-                    ('integer', 'not in', []),
-                    ])
-            self.assertEqual(integers, [integer1])
+        numeric1, numeric2 = Numeric.create([{
+                    'numeric': Decimal('1.1'),
+                    }, {
+                    'numeric': Decimal('100.0'),
+                    }])
+        numerics = Numeric.search([
+                ('numeric', '<', Decimal('5')),
+                ])
+        self.assertEqual(numerics, [numeric1])
 
-            integers = self.integer.search([
-                    ('integer', '<', 5),
-                    ])
-            self.assertEqual(integers, [integer1])
+    @with_transaction()
+    def test_numeric_search_none(self):
+        'Test numeric search with None'
+        pool = Pool()
+        Numeric = pool.get('test.numeric')
+
+        numeric_none, numeric0, numeric1 = Numeric.create([{
+                    'numeric': None,
+                    }, {
+                    'numeric': 0,
+                    }, {
+                    'numeric': 1,
+                    }])
+        self.assertEqual([numeric_none], Numeric.search([
+                    ('numeric', '=', None),
+                    ]))
+        self.assertEqual([numeric0], Numeric.search([
+                    ('numeric', '=', 0),
+                    ]))
+        self.assertEqual([numeric1], Numeric.search([
+                    ('numeric', '>', 0),
+                    ]))
+
+        self.assertEqual([numeric0, numeric1], Numeric.search([
+                    ('numeric', '!=', None),
+                    ]))
+        self.assertEqual([numeric1], Numeric.search([
+                    ('numeric', '!=', 0),
+                    ]))
+        self.assertEqual([numeric0], Numeric.search([
+                    ('numeric', '<', 1),
+                    ]))
+
+        self.assertEqual([numeric_none, numeric1], Numeric.search([
+                    'OR',
+                    ('numeric', '>', 0),
+                    ('numeric', '=', None),
+                    ]))
+
+    @with_transaction()
+    def test_char(self):
+        'Test Char'
+        pool = Pool()
+        Char = pool.get('test.char')
+        CharDefault = pool.get('test.char_default')
+        CharRequired = pool.get('test.char_required')
+        CharSize = pool.get('test.char_size')
+        CharTranslate = pool.get('test.char_translate')
+        transaction = Transaction()
+
+        for char in (CharTranslate, Char):
+            char1, = char.create([{
+                        'char': 'Test',
+                        }])
+            self.assert_(char1)
+            self.assertEqual(char1.char, 'Test')
 
-            integers = self.integer.search([
-                    ('integer', '<', -5),
+            chars = char.search([
+                    ('char', '=', 'Test'),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', '<', 1),
+            chars = char.search([
+                    ('char', '=', 'Foo'),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '<=', 5),
+            chars = char.search([
+                    ('char', '=', None),
                     ])
-            self.assertEqual(integers, [integer1])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '<=', -5),
+            chars = char.search([
+                    ('char', '!=', 'Test'),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '<=', 1),
+            chars = char.search([
+                    ('char', '!=', 'Foo'),
                     ])
-            self.assertEqual(integers, [integer1])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', '>', 5),
+            chars = char.search([
+                    ('char', '!=', None),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', '>', -5),
+            chars = char.search([
+                    ('char', 'in', ['Test']),
                     ])
-            self.assertEqual(integers, [integer1])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', '>', 1),
+            chars = char.search([
+                    ('char', 'in', ['Foo']),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '>=', 5),
+            chars = char.search([
+                    ('char', 'in', [None]),
                     ])
-            self.assertEqual(integers, [])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '>=', -5),
+            chars = char.search([
+                    ('char', 'in', []),
                     ])
-            self.assertEqual(integers, [integer1])
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '>=', 1),
+            chars = char.search([
+                    ('char', 'not in', ['Test']),
                     ])
-            self.assertEqual(integers, [integer1])
-
-            integer2, = self.integer.create([{
-                        'integer': 0,
-                        }])
-            self.assert_(integer2)
-            self.assertEqual(integer2.integer, 0)
+            self.assertEqual(chars, [])
 
-            integers = self.integer.search([
-                    ('integer', '=', 0),
+            chars = char.search([
+                    ('char', 'not in', ['Foo']),
                     ])
-            self.assertEqual(integers, [integer2])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', 'in', [0, 1]),
+            chars = char.search([
+                    ('char', 'not in', [None]),
                     ])
-            self.assertEqual(integers, [integer1, integer2])
+            self.assertEqual(chars, [char1])
 
-            integers = self.integer.search([
-                    ('integer', 'not in', [0, 1]),
+            chars = char.search([
+                    ('char', 'not in', []),
                     ])
-            self.assertEqual(integers, [])
-
-            integer3, = self.integer.create([{}])
-            self.assert_(integer3)
-            self.assertEqual(integer3.integer, None)
-
-            integer4, = self.integer_default.create([{}])
-            self.assert_(integer4)
-            self.assertEqual(integer4.integer, 5)
-
-            self.integer.write([integer1], {
-                    'integer': 0,
-                    })
-            self.assertEqual(integer1.integer, 0)
-
-            self.integer.write([integer2], {
-                    'integer': 1,
-                    })
-            self.assertEqual(integer2.integer, 1)
-
-            self.assertRaises(Exception, self.integer.create, [{
-                        'integer': 'test',
-                        }])
-
-            self.assertRaises(Exception, self.integer.write, [integer1], {
-                    'integer': 'test',
-                    })
-
-            # We should catch UserError but mysql does not raise an
-            # IntegrityError but an OperationalError
-            self.assertRaises(Exception, self.integer_required.create, [{}])
-            transaction.cursor.rollback()
-
-            integer5, = self.integer_required.create([{
-                        'integer': 0,
-                        }])
-            self.assert_(integer5)
-            self.assertEqual(integer5.integer, 0)
-
-            transaction.cursor.rollback()
-
-    def test0021integer(self):
-        'Test Integer with domain'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.integer_domain.create([{
-                        'integer': 100,
-                        }])
-            self.assertRaises(UserError, self.integer_domain.create, [{
-                        'integer': 10,
-                        }])
-
-    def test0030float(self):
-        'Test Float'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            float1, = self.float.create([{
-                        'float': 1.1,
-                        }])
-            self.assert_(float1)
-            self.assertEqual(float1.float, 1.1)
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '=', 1.1),
+            chars = char.search([
+                    ('char', 'like', 'Test'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '=', 0),
+            chars = char.search([
+                    ('char', 'like', 'T%'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '!=', 1.1),
+            chars = char.search([
+                    ('char', 'like', 'Foo'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', '!=', 0),
+            chars = char.search([
+                    ('char', 'like', 'F%'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', 'in', [1.1]),
+            chars = char.search([
+                    ('char', 'ilike', 'test'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', 'in', [0]),
+            chars = char.search([
+                    ('char', 'ilike', 't%'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', 'in', []),
+            chars = char.search([
+                    ('char', 'ilike', 'foo'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', 'not in', [1.1]),
+            chars = char.search([
+                    ('char', 'ilike', 'f%'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', 'not in', [0]),
+            chars = char.search([
+                    ('char', 'not like', 'Test'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', 'not in', []),
+            chars = char.search([
+                    ('char', 'not like', 'T%'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', '<', 5),
+            chars = char.search([
+                    ('char', 'not like', 'Foo'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '<', -5),
+            chars = char.search([
+                    ('char', 'not like', 'F%'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '<', 1.1),
+            chars = char.search([
+                    ('char', 'not ilike', 'test'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', '<=', 5),
+            chars = char.search([
+                    ('char', 'not ilike', 't%'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', '<=', -5),
+            chars = char.search([
+                    ('char', 'not ilike', 'foo'),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '<=', 1.1),
+            chars = char.search([
+                    ('char', 'not ilike', 'f%'),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [char1])
 
-            floats = self.float.search([
-                    ('float', '>', 5),
-                    ])
-            self.assertEqual(floats, [])
+            char2, = char.create([{
+                        'char': None,
+                        }])
+            self.assert_(char2)
+            self.assertEqual(char2.char, None)
 
-            floats = self.float.search([
-                    ('float', '>', -5),
+            chars = char.search([
+                    ('char', '=', None),
                     ])
-            self.assertEqual(floats, [float1])
+            self.assertEqual(chars, [char2])
 
-            floats = self.float.search([
-                    ('float', '>', 1.1),
+            chars = char.search([
+                    ('char', 'in', [None, 'Test']),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [char1, char2])
 
-            floats = self.float.search([
-                    ('float', '>=', 5),
+            chars = char.search([
+                    ('char', 'not in', [None, 'Test']),
                     ])
-            self.assertEqual(floats, [])
+            self.assertEqual(chars, [])
 
-            floats = self.float.search([
-                    ('float', '>=', -5),
-                    ])
-            self.assertEqual(floats, [float1])
+        char3, = Char.create([{}])
+        self.assert_(char3)
+        self.assertEqual(char3.char, None)
 
-            floats = self.float.search([
-                    ('float', '>=', 1.1),
-                    ])
-            self.assertEqual(floats, [float1])
+        char4, = CharDefault.create([{}])
+        self.assert_(char4)
+        self.assertEqual(char4.char, 'Test')
 
-            float2, = self.float.create([{
-                        'float': 0,
-                        }])
-            self.assert_(float2)
-            self.assertEqual(float2.float, 0)
+        Char.write([char1], {
+                'char': None,
+                })
+        self.assertEqual(char1.char, None)
 
-            floats = self.float.search([
-                    ('float', '=', 0),
-                    ])
-            self.assertEqual(floats, [float2])
+        Char.write([char2], {
+                'char': 'Test',
+                })
+        self.assertEqual(char2.char, 'Test')
 
-            floats = self.float.search([
-                    ('float', 'in', [0, 1.1]),
-                    ])
-            self.assertEqual(floats, [float1, float2])
+        self.assertRaises(UserError, CharRequired.create, [{}])
+        transaction.rollback()
 
-            floats = self.float.search([
-                    ('float', 'not in', [0, 1.1]),
-                    ])
-            self.assertEqual(floats, [])
+        self.assertRaises(UserError, CharRequired.create, [{
+                'char': '',
+                }])
+        transaction.rollback()
 
-            float3, = self.float.create([{}])
-            self.assert_(float3)
-            self.assertEqual(float3.float, None)
+        char5, = CharRequired.create([{
+                    'char': 'Test',
+                    }])
+        self.assert_(char5)
 
-            float4, = self.float_default.create([{}])
-            self.assert_(float4)
-            self.assertEqual(float4.float, 5.5)
+        char6, = CharSize.create([{
+                    'char': 'Test',
+                    }])
+        self.assert_(char6)
 
-            self.float.write([float1], {
-                    'float': 0,
-                    })
-            self.assertEqual(float1.float, 0)
+        self.assertRaises(Exception, CharSize.create, [{
+                'char': 'foobar',
+                }])
 
-            self.float.write([float2], {
-                    'float': 1.1,
-                    })
-            self.assertEqual(float2.float, 1.1)
+        self.assertRaises(Exception, CharSize.write, [char6], {
+                'char': 'foobar',
+                })
+        transaction.rollback()
 
-            self.assertRaises(Exception, self.float.create, [{
-                        'float': 'test',
+        char7, = Char.create([{
+                    'char': u'é',
+                    }])
+        self.assert_(char7)
+        self.assertEqual(char7.char, u'é')
+
+        chars = Char.search([
+                ('char', '=', u'é'),
+                ])
+        self.assertEqual(chars, [char7])
+
+        Char.write([char7], {
+                'char': 'é',
+                })
+        self.assertEqual(char7.char, u'é')
+
+        chars = Char.search([
+                ('char', '=', 'é'),
+                ])
+        self.assertEqual(chars, [char7])
+
+    @with_transaction()
+    def test_text(self):
+        'Test Text'
+        pool = Pool()
+        Text = pool.get('test.text')
+        TextDefault = pool.get('test.text_default')
+        TextRequired = pool.get('test.text_required')
+        TextSize = pool.get('test.text_size')
+        TextTranslate = pool.get('test.text_translate')
+        transaction = Transaction()
+
+        for text in (TextTranslate, Text):
+            text1, = text.create([{
+                        'text': 'Test',
                         }])
+            self.assert_(text1)
+            self.assertEqual(text1.text, 'Test')
 
-            self.assertRaises(Exception, self.float.write, [float1], {
-                    'float': 'test',
-                    })
-
-            self.assertRaises(UserError, self.float_required.create, [{}])
-            transaction.cursor.rollback()
-
-            float5, = self.float_required.create([{
-                        'float': 0.0,
-                        }])
-            self.assertEqual(float5.float, 0.0)
+            texts = text.search([
+                    ('text', '=', 'Test'),
+                    ])
+            self.assertEqual(texts, [text1])
 
-            float6, = self.float_digits.create([{
-                        'digits': 1,
-                        'float': 1.1,
-                        }])
-            self.assert_(float6)
+            texts = text.search([
+                    ('text', '=', 'Foo'),
+                    ])
+            self.assertEqual(texts, [])
 
-            self.assertRaises(UserError, self.float_digits.create, [{
-                        'digits': 1,
-                        'float': 1.11,
-                        }])
+            texts = text.search([
+                    ('text', '=', None),
+                    ])
+            self.assertEqual(texts, [])
 
-            self.assertRaises(UserError, self.float_digits.write,
-                [float6], {
-                    'float': 1.11,
-                    })
+            texts = text.search([
+                    ('text', '!=', 'Test'),
+                    ])
+            self.assertEqual(texts, [])
 
-            self.assertRaises(UserError, self.float_digits.write,
-                [float6], {
-                    'digits': 0,
-                    })
+            texts = text.search([
+                    ('text', '!=', 'Foo'),
+                    ])
+            self.assertEqual(texts, [text1])
 
-            float7, = self.float.create([{
-                        'float': 0.123456789012345,
-                        }])
-            self.assertEqual(float7.float, 0.123456789012345)
+            texts = text.search([
+                    ('text', '!=', None),
+                    ])
+            self.assertEqual(texts, [text1])
 
-            transaction.cursor.rollback()
+            texts = text.search([
+                    ('text', 'in', ['Test']),
+                    ])
+            self.assertEqual(texts, [text1])
 
-    def test0031float(self):
-        'Test float search with None'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            float_none, float0, float1 = self.float.create([{
-                        'float': None,
-                        }, {
-                        'float': 0,
-                        }, {
-                        'float': 1,
-                        }])
-            self.assertEqual([float_none], self.float.search([
-                        ('float', '=', None),
-                        ]))
-            self.assertEqual([float0], self.float.search([
-                        ('float', '=', 0),
-                        ]))
-            self.assertEqual([float1], self.float.search([
-                        ('float', '>', 0),
-                        ]))
-
-            self.assertEqual([float0, float1], self.float.search([
-                        ('float', '!=', None),
-                        ]))
-            self.assertEqual([float1], self.float.search([
-                        ('float', '!=', 0),
-                        ]))
-            self.assertEqual([float0], self.float.search([
-                        ('float', '<', 1),
-                        ]))
-
-            self.assertEqual([float_none, float1], self.float.search([
-                        'OR',
-                        ('float', '>', 0),
-                        ('float', '=', None),
-                        ]))
-
-    def test0040numeric(self):
-        'Test Numeric'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            numeric1, = self.numeric.create([{
-                        'numeric': Decimal('1.1'),
-                        }])
-            self.assert_(numeric1)
-            self.assertEqual(numeric1.numeric, Decimal('1.1'))
+            texts = text.search([
+                    ('text', 'in', ['Foo']),
+                    ])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '=', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'in', [None]),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '=', Decimal('0')),
+            texts = text.search([
+                    ('text', 'in', []),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '!=', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'not in', ['Test']),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '!=', Decimal('0')),
+            texts = text.search([
+                    ('text', 'not in', ['Foo']),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'in', [Decimal('1.1')]),
+            texts = text.search([
+                    ('text', 'not in', [None]),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'in', [Decimal('0')]),
+            texts = text.search([
+                    ('text', 'not in', []),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'in', []),
+            texts = text.search([
+                    ('text', 'like', 'Test'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'not in', [Decimal('1.1')]),
+            texts = text.search([
+                    ('text', 'like', 'T%'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'not in', [Decimal('0')]),
+            texts = text.search([
+                    ('text', 'like', 'Foo'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'not in', []),
+            texts = text.search([
+                    ('text', 'like', 'F%'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<', Decimal('5')),
+            texts = text.search([
+                    ('text', 'ilike', 'test'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<', Decimal('-5')),
+            texts = text.search([
+                    ('text', 'ilike', 't%'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'ilike', 'foo'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<=', Decimal('5')),
+            texts = text.search([
+                    ('text', 'ilike', 'f%'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<=', Decimal('-5')),
+            texts = text.search([
+                    ('text', 'not like', 'Test'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '<=', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'not like', 'T%'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>', Decimal('5')),
+            texts = text.search([
+                    ('text', 'not like', 'Foo'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>', Decimal('-5')),
+            texts = text.search([
+                    ('text', 'not like', 'F%'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'not ilike', 'test'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>=', Decimal('5')),
+            texts = text.search([
+                    ('text', 'not ilike', 't%'),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>=', Decimal('-5')),
+            texts = text.search([
+                    ('text', 'not ilike', 'foo'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numerics = self.numeric.search([
-                    ('numeric', '>=', Decimal('1.1')),
+            texts = text.search([
+                    ('text', 'not ilike', 'f%'),
                     ])
-            self.assertEqual(numerics, [numeric1])
+            self.assertEqual(texts, [text1])
 
-            numeric2, = self.numeric.create([{
-                        'numeric': Decimal('0'),
+            text2, = text.create([{
+                        'text': None,
                         }])
-            self.assert_(numeric2)
-            self.assertEqual(numeric2.numeric, Decimal('0'))
+            self.assert_(text2)
+            self.assertEqual(text2.text, None)
 
-            numerics = self.numeric.search([
-                    ('numeric', '=', Decimal('0')),
+            texts = text.search([
+                    ('text', '=', None),
                     ])
-            self.assertEqual(numerics, [numeric2])
+            self.assertEqual(texts, [text2])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'in', [Decimal('0'), Decimal('1.1')]),
+            texts = text.search([
+                    ('text', 'in', [None, 'Test']),
                     ])
-            self.assertEqual(numerics, [numeric1, numeric2])
+            self.assertEqual(texts, [text1, text2])
 
-            numerics = self.numeric.search([
-                    ('numeric', 'not in', [Decimal('0'), Decimal('1.1')]),
+            texts = text.search([
+                    ('text', 'not in', [None, 'Test']),
                     ])
-            self.assertEqual(numerics, [])
+            self.assertEqual(texts, [])
 
-            numeric3, = self.numeric.create([{}])
-            self.assert_(numeric3)
-            self.assertEqual(numeric3.numeric, None)
+        text3, = Text.create([{}])
+        self.assert_(text3)
+        self.assertEqual(text3.text, None)
 
-            numeric4, = self.numeric_default.create([{}])
-            self.assert_(numeric4)
-            self.assertEqual(numeric4.numeric, Decimal('5.5'))
+        text4, = TextDefault.create([{}])
+        self.assert_(text4)
+        self.assertEqual(text4.text, 'Test')
 
-            self.numeric.write([numeric1], {
-                    'numeric': Decimal('0'),
-                    })
-            self.assertEqual(numeric1.numeric, Decimal('0'))
+        Text.write([text1], {
+                'text': None,
+                })
+        self.assertEqual(text1.text, None)
 
-            self.numeric.write([numeric2], {
-                    'numeric': Decimal('1.1'),
-                    })
-            self.assertEqual(numeric2.numeric, Decimal('1.1'))
+        Text.write([text2], {
+                'text': 'Test',
+                })
+        self.assertEqual(text2.text, 'Test')
 
-            self.assertRaises(Exception, self.numeric.create, [{
-                        'numeric': 'test',
-                        }])
+        self.assertRaises(UserError, TextRequired.create, [{}])
+        transaction.rollback()
 
-            self.assertRaises(Exception, self.numeric.write, [numeric1], {
-                    'numeric': 'test',
-                    })
+        text5, = TextRequired.create([{
+                    'text': 'Test',
+                    }])
+        self.assert_(text5)
 
-            self.assertRaises(UserError, self.numeric_required.create, [{}])
-            transaction.cursor.rollback()
+        text6, = TextSize.create([{
+                    'text': 'Test',
+                    }])
+        self.assert_(text6)
 
-            numeric5, = self.numeric_required.create([{
-                    'numeric': Decimal(0),
+        self.assertRaises(UserError, TextSize.create, [{
+                    'text': 'foobar',
                     }])
-            self.assertEqual(numeric5.numeric, 0)
 
-            numeric6, = self.numeric_digits.create([{
-                        'digits': 1,
-                        'numeric': Decimal('1.1'),
-                        }])
-            self.assert_(numeric6)
+        self.assertRaises(UserError, TextSize.write, [text6], {
+                'text': 'foobar',
+                })
 
-            self.assertRaises(UserError, self.numeric_digits.create, [{
-                        'digits': 1,
-                        'numeric': Decimal('1.11'),
-                        }])
+        text7, = Text.create([{
+                    'text': 'Foo\nBar',
+                    }])
+        self.assert_(text7)
 
-            self.assertRaises(UserError, self.numeric_digits.write,
-                [numeric6], {
-                    'numeric': Decimal('1.11'),
-                    })
+        text8, = Text.create([{
+                    'text': u'é',
+                    }])
+        self.assert_(text8)
+        self.assertEqual(text8.text, u'é')
+
+        texts = Text.search([
+                ('text', '=', u'é'),
+                ])
+        self.assertEqual(texts, [text8])
+
+        Text.write([text8], {
+                'text': 'é',
+                })
+        self.assertEqual(text8.text, u'é')
+
+        texts = Text.search([
+                ('text', '=', 'é'),
+                ])
+        self.assertEqual(texts, [text8])
+
+    @with_transaction()
+    def test_date(self):
+        'Test Date'
+        pool = Pool()
+        Date = pool.get('test.date')
+        DateDefault = pool.get('test.date_default')
+        DateRequired = pool.get('test.date_required')
+        transaction = Transaction()
+
+        today = datetime.date(2009, 1, 1)
+        tomorrow = today + datetime.timedelta(1)
+        yesterday = today - datetime.timedelta(1)
+        default_date = datetime.date(2000, 1, 1)
+
+        date1, = Date.create([{
+                    'date': today,
+                    }])
+        self.assert_(date1)
+        self.assertEqual(date1.date, today)
+
+        dates = Date.search([
+                ('date', '=', today),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '=', tomorrow),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '=', None),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '!=', today),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '!=', tomorrow),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '!=', None),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', 'in', [today]),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', 'in', [tomorrow]),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', 'in', [None]),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', 'in', []),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', 'not in', [today]),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', 'not in', [tomorrow]),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', 'not in', [None]),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', 'not in', []),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '<', tomorrow),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '<', yesterday),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '<', today),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '<=', today),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '<=', yesterday),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '<=', tomorrow),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '>', tomorrow),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '>', yesterday),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '>', today),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '>=', tomorrow),
+                ])
+        self.assertEqual(dates, [])
+
+        dates = Date.search([
+                ('date', '>=', yesterday),
+                ])
+        self.assertEqual(dates, [date1])
+
+        dates = Date.search([
+                ('date', '>=', today),
+                ])
+        self.assertEqual(dates, [date1])
+
+        date2, = Date.create([{
+                    'date': yesterday,
+                    }])
+        self.assert_(date2)
+        self.assertEqual(date2.date, yesterday)
+
+        dates = Date.search([
+                ('date', '=', yesterday),
+                ])
+        self.assertEqual(dates, [date2])
+
+        dates = Date.search([
+                ('date', 'in', [yesterday, today]),
+                ])
+        self.assertEqual(dates, [date1, date2])
+
+        dates = Date.search([
+                ('date', 'not in', [yesterday, today]),
+                ])
+        self.assertEqual(dates, [])
+
+        date3, = Date.create([{}])
+        self.assert_(date3)
+        self.assertEqual(date3.date, None)
+
+        date4, = DateDefault.create([{}])
+        self.assert_(date4)
+        self.assertEqual(date4.date, default_date)
+
+        Date.write([date1], {
+                'date': yesterday,
+                })
+        self.assertEqual(date1.date, yesterday)
+
+        Date.write([date2], {
+                'date': today,
+                })
+        self.assertEqual(date2.date, today)
+
+        self.assertRaises(Exception, Date.create, [{
+                    'date': 'test',
+                    }])
 
-            self.assertRaises(UserError, self.numeric_digits.write,
-                [numeric6], {
-                    'numeric': Decimal('0.10000000000000001'),
-                    })
+        self.assertRaises(Exception, Date.write, [date1], {
+                'date': 'test',
+                })
 
-            self.assertRaises(UserError, self.numeric_digits.write,
-                [numeric6], {
-                    'digits': 0,
-                    })
+        self.assertRaises(Exception, Date.create, [{
+                    'date': 1,
+                    }])
 
-            numeric7, = self.numeric.create([{
-                        'numeric': Decimal('0.1234567890123456789'),
-                        }])
-            self.assertEqual(numeric7.numeric,
-                Decimal('0.1234567890123456789'))
+        self.assertRaises(Exception, Date.write, [date1], {
+                'date': 1,
+                })
 
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Date.create, [{
+                    'date': datetime.datetime.now(),
+                    }])
 
-    def test0041numeric(self):
-        'Test numeric search cast'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            numeric1, numeric2 = self.numeric.create([{
-                        'numeric': Decimal('1.1'),
-                        }, {
-                        'numeric': Decimal('100.0'),
-                        }])
-            numerics = self.numeric.search([
-                    ('numeric', '<', Decimal('5')),
-                    ])
-            self.assertEqual(numerics, [numeric1])
+        self.assertRaises(Exception, Date.write, [date1], {
+                'date': datetime.datetime.now(),
+                })
 
-    def test0042numeric(self):
-        'Test numeric search with None'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            numeric_none, numeric0, numeric1 = self.numeric.create([{
-                        'numeric': None,
-                        }, {
-                        'numeric': 0,
-                        }, {
-                        'numeric': 1,
-                        }])
-            self.assertEqual([numeric_none], self.numeric.search([
-                        ('numeric', '=', None),
-                        ]))
-            self.assertEqual([numeric0], self.numeric.search([
-                        ('numeric', '=', 0),
-                        ]))
-            self.assertEqual([numeric1], self.numeric.search([
-                        ('numeric', '>', 0),
-                        ]))
-
-            self.assertEqual([numeric0, numeric1], self.numeric.search([
-                        ('numeric', '!=', None),
-                        ]))
-            self.assertEqual([numeric1], self.numeric.search([
-                        ('numeric', '!=', 0),
-                        ]))
-            self.assertEqual([numeric0], self.numeric.search([
-                        ('numeric', '<', 1),
-                        ]))
-
-            self.assertEqual([numeric_none, numeric1], self.numeric.search([
-                        'OR',
-                        ('numeric', '>', 0),
-                        ('numeric', '=', None),
-                        ]))
-
-    def test0050char(self):
-        'Test Char'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            for char in (self.char_translate, self.char):
-                char1, = char.create([{
-                            'char': 'Test',
-                            }])
-                self.assert_(char1)
-                self.assertEqual(char1.char, 'Test')
-
-                chars = char.search([
-                        ('char', '=', 'Test'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', '=', 'Foo'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', '=', None),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', '!=', 'Test'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', '!=', 'Foo'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', '!=', None),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'in', ['Test']),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'in', ['Foo']),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'in', [None]),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'in', []),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not in', ['Test']),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not in', ['Foo']),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'not in', [None]),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'not in', []),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'like', 'Test'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'like', 'T%'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'like', 'Foo'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'like', 'F%'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'ilike', 'test'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'ilike', 't%'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'ilike', 'foo'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'ilike', 'f%'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not like', 'Test'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not like', 'T%'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not like', 'Foo'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'not like', 'F%'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'not ilike', 'test'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not ilike', 't%'),
-                        ])
-                self.assertEqual(chars, [])
-
-                chars = char.search([
-                        ('char', 'not ilike', 'foo'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                chars = char.search([
-                        ('char', 'not ilike', 'f%'),
-                        ])
-                self.assertEqual(chars, [char1])
-
-                char2, = char.create([{
-                            'char': None,
-                            }])
-                self.assert_(char2)
-                self.assertEqual(char2.char, None)
-
-                chars = char.search([
-                        ('char', '=', None),
-                        ])
-                self.assertEqual(chars, [char2])
-
-                chars = char.search([
-                        ('char', 'in', [None, 'Test']),
-                        ])
-                self.assertEqual(chars, [char1, char2])
-
-                chars = char.search([
-                        ('char', 'not in', [None, 'Test']),
-                        ])
-                self.assertEqual(chars, [])
-
-            char3, = self.char.create([{}])
-            self.assert_(char3)
-            self.assertEqual(char3.char, None)
-
-            char4, = self.char_default.create([{}])
-            self.assert_(char4)
-            self.assertEqual(char4.char, 'Test')
-
-            self.char.write([char1], {
-                    'char': None,
-                    })
-            self.assertEqual(char1.char, None)
+        self.assertRaises(Exception, Date.create, [{
+                    'date': '2009-13-01',
+                    }])
 
-            self.char.write([char2], {
-                    'char': 'Test',
-                    })
-            self.assertEqual(char2.char, 'Test')
+        self.assertRaises(Exception, Date.write, [date1], {
+                'date': '2009-02-29',
+                })
 
-            self.assertRaises(UserError, self.char_required.create, [{}])
-            transaction.cursor.rollback()
+        date5, = Date.create([{
+                    'date': '2009-01-01',
+                    }])
+        self.assert_(date5)
+        self.assertEqual(date5.date, datetime.date(2009, 1, 1))
+
+        self.assertRaises(UserError, DateRequired.create, [{}])
+        transaction.rollback()
 
-            self.assertRaises(UserError, self.char_required.create, [{
-                    'char': '',
+        date6, = DateRequired.create([{
+                    'date': today,
                     }])
-            transaction.cursor.rollback()
+        self.assert_(date6)
 
-            char5, = self.char_required.create([{
-                        'char': 'Test',
-                        }])
-            self.assert_(char5)
+        date7, = Date.create([{
+                    'date': None,
+                    }])
+        self.assert_(date7)
 
-            char6, = self.char_size.create([{
-                        'char': 'Test',
-                        }])
-            self.assert_(char6)
+        date8, = Date.create([{
+                    'date': None,
+                    }])
+        self.assert_(date8)
 
-            self.assertRaises(Exception, self.char_size.create, [{
-                    'char': 'foobar',
+    @with_transaction()
+    def test_datetime(self):
+        'Test DateTime'
+        pool = Pool()
+        Datetime = pool.get('test.datetime')
+        DatetimeDefault = pool.get('test.datetime_default')
+        DatetimeRequired = pool.get('test.datetime_required')
+        DatetimeFormat = pool.get('test.datetime_format')
+        transaction = Transaction()
+
+        today = datetime.datetime(2009, 1, 1, 12, 0, 0)
+        tomorrow = today + datetime.timedelta(1)
+        yesterday = today - datetime.timedelta(1)
+        default_datetime = datetime.datetime(2000, 1, 1, 12, 0, 0)
+
+        datetime1, = Datetime.create([{
+                    'datetime': today,
+                    }])
+        self.assert_(datetime1)
+        self.assertEqual(datetime1.datetime, today)
+
+        datetimes = Datetime.search([
+                ('datetime', '=', today),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '=', tomorrow),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '=', None),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '!=', today),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '!=', tomorrow),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '!=', None),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', 'in', [today]),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', 'in', [tomorrow]),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', 'in', [None]),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', 'in', []),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', 'not in', [today]),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', 'not in', [tomorrow]),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', 'not in', [None]),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', 'not in', []),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '<', tomorrow),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '<', yesterday),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '<', today),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '<=', today),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '<=', yesterday),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '<=', tomorrow),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '>', tomorrow),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '>', yesterday),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '>', today),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '>=', tomorrow),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetimes = Datetime.search([
+                ('datetime', '>=', yesterday),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetimes = Datetime.search([
+                ('datetime', '>=', today),
+                ])
+        self.assertEqual(datetimes, [datetime1])
+
+        datetime2, = Datetime.create([{
+                    'datetime': yesterday,
+                    }])
+        self.assert_(datetime2)
+        self.assertEqual(datetime2.datetime, yesterday)
+
+        datetimes = Datetime.search([
+                ('datetime', '=', yesterday),
+                ])
+        self.assertEqual(datetimes, [datetime2])
+
+        datetimes = Datetime.search([
+                ('datetime', 'in', [yesterday, today]),
+                ])
+        self.assertEqual(datetimes, [datetime1, datetime2])
+
+        datetimes = Datetime.search([
+                ('datetime', 'not in', [yesterday, today]),
+                ])
+        self.assertEqual(datetimes, [])
+
+        datetime3, = Datetime.create([{}])
+        self.assert_(datetime3)
+        self.assertEqual(datetime3.datetime, None)
+
+        datetime4, = DatetimeDefault.create([{}])
+        self.assert_(datetime4)
+        self.assertEqual(datetime4.datetime, default_datetime)
+
+        Datetime.write([datetime1], {
+                'datetime': yesterday,
+                })
+        self.assertEqual(datetime1.datetime, yesterday)
+
+        Datetime.write([datetime2], {
+                'datetime': today,
+                })
+        self.assertEqual(datetime2.datetime, today)
+
+        self.assertRaises(Exception, Datetime.create, [{
+                    'datetime': 'test',
                     }])
 
-            self.assertRaises(Exception, self.char_size.write, [char6], {
-                    'char': 'foobar',
-                    })
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Datetime.write, [datetime1],
+            {
+                'datetime': 'test',
+                })
 
-            char7, = self.char.create([{
-                        'char': u'é',
-                        }])
-            self.assert_(char7)
-            self.assertEqual(char7.char, u'é')
+        self.assertRaises(Exception, Datetime.create, [{
+                    'datetime': 1,
+                    }])
 
-            chars = self.char.search([
-                    ('char', '=', u'é'),
-                    ])
-            self.assertEqual(chars, [char7])
+        self.assertRaises(Exception, Datetime.write, [datetime1],
+            {
+                'datetime': 1,
+                })
 
-            self.char.write([char7], {
-                    'char': 'é',
-                    })
-            self.assertEqual(char7.char, u'é')
+        self.assertRaises(Exception, Datetime.create, [{
+                    'datetime': datetime.date.today(),
+                    }])
 
-            chars = self.char.search([
-                    ('char', '=', 'é'),
-                    ])
-            self.assertEqual(chars, [char7])
+        self.assertRaises(Exception, Datetime.write, [datetime1],
+            {
+                'datetime': datetime.date.today(),
+                })
 
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Datetime.create, [{
+                    'datetime': '2009-13-01 12:30:00',
+                    }])
 
-    def test0060text(self):
-        'Test Text'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            for text in (self.text_translate, self.text):
-                text1, = text.create([{
-                            'text': 'Test',
-                            }])
-                self.assert_(text1)
-                self.assertEqual(text1.text, 'Test')
-
-                texts = text.search([
-                        ('text', '=', 'Test'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', '=', 'Foo'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', '=', None),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', '!=', 'Test'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', '!=', 'Foo'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', '!=', None),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'in', ['Test']),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'in', ['Foo']),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'in', [None]),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'in', []),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not in', ['Test']),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not in', ['Foo']),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'not in', [None]),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'not in', []),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'like', 'Test'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'like', 'T%'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'like', 'Foo'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'like', 'F%'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'ilike', 'test'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'ilike', 't%'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'ilike', 'foo'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'ilike', 'f%'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not like', 'Test'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not like', 'T%'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not like', 'Foo'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'not like', 'F%'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'not ilike', 'test'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not ilike', 't%'),
-                        ])
-                self.assertEqual(texts, [])
-
-                texts = text.search([
-                        ('text', 'not ilike', 'foo'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                texts = text.search([
-                        ('text', 'not ilike', 'f%'),
-                        ])
-                self.assertEqual(texts, [text1])
-
-                text2, = text.create([{
-                            'text': None,
-                            }])
-                self.assert_(text2)
-                self.assertEqual(text2.text, None)
-
-                texts = text.search([
-                        ('text', '=', None),
-                        ])
-                self.assertEqual(texts, [text2])
-
-                texts = text.search([
-                        ('text', 'in', [None, 'Test']),
-                        ])
-                self.assertEqual(texts, [text1, text2])
-
-                texts = text.search([
-                        ('text', 'not in', [None, 'Test']),
-                        ])
-                self.assertEqual(texts, [])
-
-            text3, = self.text.create([{}])
-            self.assert_(text3)
-            self.assertEqual(text3.text, None)
-
-            text4, = self.text_default.create([{}])
-            self.assert_(text4)
-            self.assertEqual(text4.text, 'Test')
-
-            self.text.write([text1], {
-                    'text': None,
-                    })
-            self.assertEqual(text1.text, None)
+        self.assertRaises(Exception, Datetime.write, [datetime1],
+            {
+                'datetime': '2009-02-29 12:30:00',
+                })
 
-            self.text.write([text2], {
-                    'text': 'Test',
-                    })
-            self.assertEqual(text2.text, 'Test')
+        self.assertRaises(Exception, Datetime.write, [datetime1],
+            {
+                'datetime': '2009-01-01 25:00:00',
+                })
 
-            self.assertRaises(UserError, self.text_required.create, [{}])
-            transaction.cursor.rollback()
+        datetime5, = Datetime.create([{
+                'datetime': '2009-01-01 12:00:00',
+                }])
+        self.assert_(datetime5)
+        self.assertEqual(datetime5.datetime,
+            datetime.datetime(2009, 1, 1, 12, 0, 0))
 
-            text5, = self.text_required.create([{
-                        'text': 'Test',
-                        }])
-            self.assert_(text5)
+        self.assertRaises(UserError, DatetimeRequired.create, [{}])
+        transaction.rollback()
 
-            text6, = self.text_size.create([{
-                        'text': 'Test',
-                        }])
-            self.assert_(text6)
+        datetime6, = DatetimeRequired.create([{
+                    'datetime': today,
+                    }])
+        self.assert_(datetime6)
 
-            self.assertRaises(UserError, self.text_size.create, [{
-                        'text': 'foobar',
-                        }])
+        datetime7, = Datetime.create([{
+                    'datetime': None,
+                    }])
+        self.assert_(datetime7)
 
-            self.assertRaises(UserError, self.text_size.write, [text6], {
-                    'text': 'foobar',
-                    })
+        datetime8, = Datetime.create([{
+                    'datetime': None,
+                    }])
+        self.assert_(datetime8)
 
-            text7, = self.text.create([{
-                        'text': 'Foo\nBar',
-                        }])
-            self.assert_(text7)
+        datetime9, = Datetime.create([{
+                    'datetime': today.replace(microsecond=1),
+                    }])
+        self.assert_(datetime9)
+        self.assertEqual(datetime9.datetime, today)
 
-            text8, = self.text.create([{
-                        'text': u'é',
-                        }])
-            self.assert_(text8)
-            self.assertEqual(text8.text, u'é')
+        # Test format
+        self.assert_(DatetimeFormat.create([{
+                        'datetime': datetime.datetime(2009, 1, 1, 12, 30),
+                        }]))
+        self.assertRaises(UserError, DatetimeFormat.create, [{
+                    'datetime': datetime.datetime(2009, 1, 1, 12, 30, 25),
+                    }])
 
-            texts = self.text.search([
-                    ('text', '=', u'é'),
-                    ])
-            self.assertEqual(texts, [text8])
+    @with_transaction()
+    def test_time(self):
+        'Test Time'
+        pool = Pool()
+        Time = pool.get('test.time')
+        TimeDefault = pool.get('test.time_default')
+        TimeRequired = pool.get('test.time_required')
+        TimeFormat = pool.get('test.time_format')
+        transaction = Transaction()
+
+        pre_evening = datetime.time(16, 30)
+        evening = datetime.time(18, 45, 3)
+        night = datetime.time(20, 00)
+        default_time = datetime.time(16, 30)
+
+        time1, = Time.create([{
+                    'time': evening,
+                    }])
+        self.assert_(time1)
+        self.assertEqual(time1.time, evening)
+
+        times = Time.search([
+                ('time', '=', evening),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '=', night),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '=', None),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '!=', evening),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '!=', night),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '!=', None),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', 'in', [evening]),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', 'in', [night]),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', 'in', [None]),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', 'in', []),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', 'not in', [evening]),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', 'not in', [night]),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', 'not in', [None]),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', 'not in', []),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '<', night),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '<', pre_evening),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '<', evening),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '<=', evening),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '<=', pre_evening),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '<=', night),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '>', night),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '>', pre_evening),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '>', evening),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '>=', night),
+                ])
+        self.assertEqual(times, [])
+
+        times = Time.search([
+                ('time', '>=', pre_evening),
+                ])
+        self.assertEqual(times, [time1])
+
+        times = Time.search([
+                ('time', '>=', evening),
+                ])
+        self.assertEqual(times, [time1])
+
+        time2, = Time.create([{
+                    'time': pre_evening,
+                    }])
+        self.assert_(time2)
+        self.assertEqual(time2.time, pre_evening)
+
+        times = Time.search([
+                ('time', '=', pre_evening),
+                ])
+        self.assertEqual(times, [time2])
+
+        times = Time.search([
+                ('time', 'in', [pre_evening, evening]),
+                ])
+        self.assertEqual(times, [time1, time2])
+
+        times = Time.search([
+                ('time', 'not in', [pre_evening, evening]),
+                ])
+        self.assertEqual(times, [])
+
+        time3, = Time.create([{}])
+        self.assert_(time3)
+        self.assertEqual(time3.time, None)
+
+        time4, = TimeDefault.create([{}])
+        self.assert_(time4)
+        self.assertEqual(time4.time, default_time)
+
+        Time.write([time1], {
+                'time': pre_evening,
+                })
+        self.assertEqual(time1.time, pre_evening)
+
+        Time.write([time2], {
+                'time': evening,
+                })
+        self.assertEqual(time2.time, evening)
+
+        self.assertRaises(Exception, Time.create, [{
+                    'time': 'test',
+                    }])
 
-            self.text.write([text8], {
-                    'text': 'é',
-                    })
-            self.assertEqual(text8.text, u'é')
+        self.assertRaises(Exception, Time.write, [time1],
+            {
+                'time': 'test',
+                })
 
-            texts = self.text.search([
-                    ('text', '=', 'é'),
-                    ])
-            self.assertEqual(texts, [text8])
+        self.assertRaises(Exception, Time.create, [{
+                'time': 1,
+                }])
 
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Time.write, [time1],
+            {
+                'time': 1,
+                })
 
-    def test0080date(self):
-        'Test Date'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            today = datetime.date(2009, 1, 1)
-            tomorrow = today + datetime.timedelta(1)
-            yesterday = today - datetime.timedelta(1)
-            default_date = datetime.date(2000, 1, 1)
-
-            date1, = self.date.create([{
-                        'date': today,
-                        }])
-            self.assert_(date1)
-            self.assertEqual(date1.date, today)
+        self.assertRaises(Exception, Time.write, [time1],
+            {
+                'time': '25:00:00',
+                })
 
-            dates = self.date.search([
-                    ('date', '=', today),
-                    ])
-            self.assertEqual(dates, [date1])
+        time5, = Time.create([{
+                    'time': '12:00:00',
+                    }])
+        self.assert_(time5)
+        self.assertEqual(time5.time, datetime.time(12, 0))
 
-            dates = self.date.search([
-                    ('date', '=', tomorrow),
-                    ])
-            self.assertEqual(dates, [])
+        self.assertRaises(UserError, TimeRequired.create, [{}])
+        transaction.rollback()
 
-            dates = self.date.search([
-                    ('date', '=', None),
-                    ])
-            self.assertEqual(dates, [])
+        time6, = TimeRequired.create([{
+                    'time': evening,
+                    }])
+        self.assert_(time6)
 
-            dates = self.date.search([
-                    ('date', '!=', today),
-                    ])
-            self.assertEqual(dates, [])
+        time7, = Time.create([{
+                    'time': None,
+                    }])
+        self.assert_(time7)
 
-            dates = self.date.search([
-                    ('date', '!=', tomorrow),
-                    ])
-            self.assertEqual(dates, [date1])
+        time9, = Time.create([{
+                    'time': evening.replace(microsecond=1),
+                    }])
+        self.assert_(time9)
+        self.assertEqual(time9.time, evening)
+
+        # Test format
+        self.assert_(TimeFormat.create([{
+                    'time': datetime.time(12, 30),
+                    }]))
+        self.assertRaises(UserError, TimeFormat.create, [{
+                'time': datetime.time(12, 30, 25),
+                }])
+
+    @with_transaction()
+    def test_one2one(self):
+        'Test One2One'
+        pool = Pool()
+        One2one = pool.get('test.one2one')
+        One2oneTarget = pool.get('test.one2one.target')
+        One2oneRequired = pool.get('test.one2one_required')
+        One2oneDomain = pool.get('test.one2one_domain')
+        transaction = Transaction()
+
+        target1, = One2oneTarget.create([{
+                    'name': 'target1',
+                    }])
+        one2one1, = One2one.create([{
+                    'name': 'origin1',
+                    'one2one': target1.id,
+                    }])
+        self.assert_(one2one1)
+        self.assertEqual(one2one1.one2one, target1)
+
+        self.assertEqual(One2one.read([one2one1.id],
+                ['one2one.name'])[0]['one2one.name'], 'target1')
+
+        one2ones = One2one.search([
+                ('one2one', '=', 'target1'),
+                ])
+        self.assertEqual(one2ones, [one2one1])
+
+        one2ones = One2one.search([
+                ('one2one', '!=', 'target1'),
+                ])
+        self.assertEqual(one2ones, [])
+
+        one2ones = One2one.search([
+                ('one2one', 'in', [target1.id]),
+                ])
+        self.assertEqual(one2ones, [one2one1])
+
+        one2ones = One2one.search([
+                ('one2one', 'in', [0]),
+                ])
+        self.assertEqual(one2ones, [])
+
+        one2ones = One2one.search([
+                ('one2one', 'not in', [target1.id]),
+                ])
+        self.assertEqual(one2ones, [])
+
+        one2ones = One2one.search([
+                ('one2one', 'not in', [0]),
+                ])
+        self.assertEqual(one2ones, [one2one1])
+
+        one2ones = One2one.search([
+                ('one2one.name', '=', 'target1'),
+                ])
+        self.assertEqual(one2ones, [one2one1])
+
+        one2ones = One2one.search([
+                ('one2one.name', '!=', 'target1'),
+                ])
+        self.assertEqual(one2ones, [])
+
+        one2one2, = One2one.create([{
+                    'name': 'origin2',
+                    }])
+        self.assert_(one2one2)
+        self.assertEqual(one2one2.one2one, None)
 
-            dates = self.date.search([
-                    ('date', '!=', None),
-                    ])
-            self.assertEqual(dates, [date1])
+        one2ones = One2one.search([
+                ('one2one', '=', None),
+                ])
+        self.assertEqual(one2ones, [one2one2])
 
-            dates = self.date.search([
-                    ('date', 'in', [today]),
-                    ])
-            self.assertEqual(dates, [date1])
+        target2, = One2oneTarget.create([{
+                    'name': 'target2',
+                    }])
+        One2one.write([one2one2], {
+                'one2one': target2.id,
+                })
+        self.assertEqual(one2one2.one2one, target2)
+
+        One2one.write([one2one2], {
+                'one2one': None,
+                })
+        self.assertEqual(one2one2.one2one, None)
+
+        self.assertRaises(UserError, One2one.create, [{
+                    'name': 'one2one3',
+                    'one2one': target1.id,
+                    }])
+        transaction.rollback()
 
-            dates = self.date.search([
-                    ('date', 'in', [tomorrow]),
-                    ])
-            self.assertEqual(dates, [])
+        self.assertRaises(UserError, One2one.write, [one2one2], {
+                'one2one': target1.id,
+                })
+        transaction.rollback()
 
-            dates = self.date.search([
-                    ('date', 'in', [None]),
-                    ])
-            self.assertEqual(dates, [])
+        self.assertRaises(UserError, One2oneRequired.create, [{
+                    'name': 'one2one3',
+                    }])
+        transaction.rollback()
 
-            dates = self.date.search([
-                    ('date', 'in', []),
-                    ])
-            self.assertEqual(dates, [])
+        target3, = One2oneTarget.create([{
+                    'name': 'target3',
+                    }])
 
-            dates = self.date.search([
-                    ('date', 'not in', [today]),
-                    ])
-            self.assertEqual(dates, [])
+        one2one3, = One2oneRequired.create([{
+                    'name': 'one2one3',
+                    'one2one': target3.id,
+                    }])
+        self.assert_(one2one3)
 
-            dates = self.date.search([
-                    ('date', 'not in', [tomorrow]),
-                    ])
-            self.assertEqual(dates, [date1])
+        target4, = One2oneTarget.create([{
+                    'name': 'target4',
+                    }])
+        self.assertRaises(UserError, One2oneDomain.create, [{
+                    'name': 'one2one4',
+                    'one2one': target4.id,
+                    }])
+        transaction.rollback()
 
-            dates = self.date.search([
-                    ('date', 'not in', [None]),
-                    ])
-            self.assertEqual(dates, [date1])
+        target5, = One2oneTarget.create([{
+                    'name': 'domain',
+                    }])
+        one2one5, = One2oneDomain.create([{
+                    'name': 'one2one5',
+                    'one2one': target5.id,
+                    }])
+        targets = One2oneTarget.create([{
+                    'name': 'multiple1',
+                    }, {
+                    'name': 'multiple2',
+                    }])
+        one2ones = One2one.create([{
+                    'name': 'origin6',
+                    'one2one': targets[0].id,
+                    }, {
+                    'name': 'origin7',
+                    'one2one': targets[1].id,
+                    }])
+        for one2one, target in zip(one2ones, targets):
+            self.assert_(one2one)
+            self.assertEqual(one2one.one2one, target)
 
-            dates = self.date.search([
-                    ('date', 'not in', []),
-                    ])
-            self.assertEqual(dates, [date1])
+    @with_transaction()
+    def test_one2many(self):
+        'Test One2Many'
+        pool = Pool()
+        One2many = pool.get('test.one2many')
+        One2manyTarget = pool.get('test.one2many.target')
+        One2manyRequired = pool.get('test.one2many_required')
+        One2manyReference = pool.get('test.one2many_reference')
+        One2manyReferenceTarget = pool.get('test.one2many_reference.target')
+        One2manySize = pool.get('test.one2many_size')
+        One2manySizePyson = pool.get('test.one2many_size_pyson')
+        transaction = Transaction()
+
+        for one2many, one2many_target in (
+                (One2many, One2manyTarget),
+                (One2manyReference, One2manyReferenceTarget),
+                ):
+            one2many1, = one2many.create([{
+                        'name': 'origin1',
+                        'targets': [
+                            ('create', [{
+                                        'name': 'target1',
+                                        }]),
+                            ],
+                        }])
+            self.assert_(one2many1)
 
-            dates = self.date.search([
-                    ('date', '<', tomorrow),
-                    ])
-            self.assertEqual(dates, [date1])
+            self.assertEqual(len(one2many1.targets), 1)
+            target1, = one2many1.targets
 
-            dates = self.date.search([
-                    ('date', '<', yesterday),
-                    ])
-            self.assertEqual(dates, [])
+            # Try with target1 stored in cache
+            target1 = one2many_target(target1.id)
+            target1.origin
+            one2many1 = one2many(one2many1)
+            self.assertEqual(one2many1.targets, (target1,))
 
-            dates = self.date.search([
-                    ('date', '<', today),
+            one2manys = one2many.search([
+                    ('targets', '=', 'target1'),
                     ])
-            self.assertEqual(dates, [])
+            self.assertEqual(one2manys, [one2many1])
 
-            dates = self.date.search([
-                    ('date', '<=', today),
+            one2manys = one2many.search([
+                    ('targets', '!=', 'target1'),
                     ])
-            self.assertEqual(dates, [date1])
+            self.assertEqual(one2manys, [])
 
-            dates = self.date.search([
-                    ('date', '<=', yesterday),
+            one2manys = one2many.search([
+                    ('targets', 'in', [target1.id]),
                     ])
-            self.assertEqual(dates, [])
+            self.assertEqual(one2manys, [one2many1])
 
-            dates = self.date.search([
-                    ('date', '<=', tomorrow),
+            one2manys = one2many.search([
+                    ('targets', 'in', [0]),
                     ])
-            self.assertEqual(dates, [date1])
+            self.assertEqual(one2manys, [])
 
-            dates = self.date.search([
-                    ('date', '>', tomorrow),
+            one2manys = one2many.search([
+                    ('targets', 'not in', (target1.id,)),
                     ])
-            self.assertEqual(dates, [])
+            self.assertEqual(one2manys, [])
 
-            dates = self.date.search([
-                    ('date', '>', yesterday),
+            one2manys = one2many.search([
+                    ('targets', 'not in', [0]),
                     ])
-            self.assertEqual(dates, [date1])
+            self.assertEqual(one2manys, [one2many1])
 
-            dates = self.date.search([
-                    ('date', '>', today),
+            one2manys = one2many.search([
+                    ('targets.name', '=', 'target1'),
                     ])
-            self.assertEqual(dates, [])
+            self.assertEqual(one2manys, [one2many1])
 
-            dates = self.date.search([
-                    ('date', '>=', tomorrow),
+            one2manys = one2many.search([
+                    ('targets.name', '!=', 'target1'),
                     ])
-            self.assertEqual(dates, [])
+            self.assertEqual(one2manys, [])
 
-            dates = self.date.search([
-                    ('date', '>=', yesterday),
+            one2manys = one2many.search([
+                    ('targets', 'where', [('name', '=', 'target1')]),
                     ])
-            self.assertEqual(dates, [date1])
-
-            dates = self.date.search([
-                    ('date', '>=', today),
+            self.assertEqual(one2manys, [one2many1])
+            one2manys = one2many.search([
+                    ('targets', 'not where', [('name', '=', 'target1')]),
                     ])
-            self.assertEqual(dates, [date1])
+            self.assertEqual(one2manys, [])
 
-            date2, = self.date.create([{
-                        'date': yesterday,
+            one2many2, = one2many.create([{
+                        'name': 'origin2',
                         }])
-            self.assert_(date2)
-            self.assertEqual(date2.date, yesterday)
+            self.assert_(one2many2)
 
-            dates = self.date.search([
-                    ('date', '=', yesterday),
-                    ])
-            self.assertEqual(dates, [date2])
-
-            dates = self.date.search([
-                    ('date', 'in', [yesterday, today]),
-                    ])
-            self.assertEqual(dates, [date1, date2])
+            self.assertEqual(one2many2.targets, ())
 
-            dates = self.date.search([
-                    ('date', 'not in', [yesterday, today]),
+            one2manys = one2many.search([
+                    ('targets', '=', None),
                     ])
-            self.assertEqual(dates, [])
-
-            date3, = self.date.create([{}])
-            self.assert_(date3)
-            self.assertEqual(date3.date, None)
-
-            date4, = self.date_default.create([{}])
-            self.assert_(date4)
-            self.assertEqual(date4.date, default_date)
-
-            self.date.write([date1], {
-                    'date': yesterday,
-                    })
-            self.assertEqual(date1.date, yesterday)
+            self.assertEqual(one2manys, [one2many2])
 
-            self.date.write([date2], {
-                    'date': today,
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('write', [target1.id], {
+                                'name': 'target1bis',
+                                }),
+                        ],
                     })
-            self.assertEqual(date2.date, today)
+            self.assertEqual(target1.name, 'target1bis')
 
-            self.assertRaises(Exception, self.date.create, [{
-                        'date': 'test',
+            target2, = one2many_target.create([{
+                        'name': 'target2',
                         }])
-
-            self.assertRaises(Exception, self.date.write, [date1], {
-                    'date': 'test',
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('add', [target2.id]),
+                        ],
                     })
+            self.assertEqual(one2many1.targets,
+                (target1, target2))
 
-            self.assertRaises(Exception, self.date.create, [{
-                        'date': 1,
-                        }])
-
-            self.assertRaises(Exception, self.date.write, [date1], {
-                    'date': 1,
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('remove', [target2.id]),
+                        ],
                     })
+            self.assertEqual(one2many1.targets, (target1,))
+            target2, = one2many_target.search([
+                    ('id', '=', target2.id),
+                    ])
+            self.assert_(target2)
 
-            self.assertRaises(Exception, self.date.create, [{
-                        'date': datetime.datetime.now(),
-                        }])
-
-            self.assertRaises(Exception, self.date.write, [date1], {
-                    'date': datetime.datetime.now(),
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('remove', [target1.id]),
+                        ],
                     })
+            self.assertEqual(one2many1.targets, ())
+            targets = one2many_target.search([
+                    ('id', 'in', [target1.id, target2.id]),
+                    ])
+            self.assertEqual(targets, [target1, target2])
 
-            self.assertRaises(Exception, self.date.create, [{
-                        'date': '2009-13-01',
-                        }])
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('add', [target1.id, target2.id]),
+                        ],
+                    })
+            self.assertEqual(one2many1.targets,
+                (target1, target2))
 
-            self.assertRaises(Exception, self.date.write, [date1], {
-                    'date': '2009-02-29',
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('copy', [target1.id], {'name': 'copy1'}),
+                        ],
                     })
+            targets = one2many_target.search([
+                    ('id', 'not in', [target1.id, target2.id]),
+                    ])
+            self.assertEqual(len(targets), 1)
+            self.assertEqual(targets[0].name, 'copy1')
 
-            date5, = self.date.create([{
-                        'date': '2009-01-01',
-                        }])
-            self.assert_(date5)
-            self.assertEqual(date5.date, datetime.date(2009, 1, 1))
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('copy', [target2.id]),
+                        ],
+                    })
+            self.assertEqual(len(one2many1.targets), 4)
+            targets = one2many_target.search([
+                    ('id', 'not in', [target1.id, target2.id]),
+                    ])
+            self.assertEqual(len(targets), 2)
+            names = set([target.name for target in targets])
+            self.assertEqual(names, set(('copy1', 'target2')))
+
+            copy_ids = [target.id for target in targets]
+            one2many.write([one2many1], {
+                    'targets': [
+                        ('delete', [target2.id] + copy_ids),
+                        ],
+                    })
+            self.assertEqual(one2many1.targets, (target1,))
+            targets = one2many_target.search([
+                    ('id', '=', target2.id),
+                    ])
+            self.assertEqual(targets, [])
 
-            self.assertRaises(UserError, self.date_required.create, [{}])
-            transaction.cursor.rollback()
+            transaction.rollback()
 
-            date6, = self.date_required.create([{
-                        'date': today,
-                        }])
-            self.assert_(date6)
+        self.assertRaises(UserError, One2manyRequired.create, [{
+                    'name': 'origin3',
+                    }])
+        transaction.rollback()
+
+        origin3_id, = One2manyRequired.create([{
+                    'name': 'origin3',
+                    'targets': [
+                        ('create', [{
+                                    'name': 'target3',
+                                    }]),
+                        ],
+                    }])
+        self.assert_(origin3_id)
 
-            date7, = self.date.create([{
-                        'date': None,
-                        }])
-            self.assert_(date7)
+        One2manySize.create([{
+                    'targets': [('create', [{}])] * 3,
+                    }])
+        self.assertRaises(UserError, One2manySize.create, [{
+                    'targets': [('create', [{}])] * 4,
+                    }])
+        One2manySizePyson.create([{
+                    'limit': 4,
+                    'targets': [('create', [{}])] * 4,
+                    }])
+        self.assertRaises(UserError, One2manySizePyson.create, [{
+                    'limit': 2,
+                    'targets': [('create', [{}])] * 4,
+                    }])
 
-            date8, = self.date.create([{
-                        'date': None,
+    @with_transaction()
+    def test_many2many(self):
+        'Test Many2Many'
+        pool = Pool()
+        Many2many = pool.get('test.many2many')
+        Many2manyTarget = pool.get('test.many2many.target')
+        Many2manyRequired = pool.get('test.many2many_required')
+        Many2manyReference = pool.get('test.many2many_reference')
+        Many2manyReferenceTarget = pool.get('test.many2many_reference.target')
+        Many2manySizeTarget = pool.get('test.many2many_size.target')
+        transaction = Transaction()
+
+        for many2many, many2many_target in (
+                (Many2many, Many2manyTarget),
+                (Many2manyReference, Many2manyReferenceTarget),
+                ):
+            many2many1, = many2many.create([{
+                        'name': 'origin1',
+                        'targets': [
+                            ('create', [{
+                                        'name': 'target1',
+                                        }]),
+                            ],
                         }])
-            self.assert_(date8)
-
-            transaction.cursor.rollback()
+            self.assert_(many2many1)
 
-    def test0090datetime(self):
-        'Test DateTime'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            today = datetime.datetime(2009, 1, 1, 12, 0, 0)
-            tomorrow = today + datetime.timedelta(1)
-            yesterday = today - datetime.timedelta(1)
-            default_datetime = datetime.datetime(2000, 1, 1, 12, 0, 0)
-
-            datetime1, = self.datetime.create([{
-                        'datetime': today,
-                        }])
-            self.assert_(datetime1)
-            self.assertEqual(datetime1.datetime, today)
+            self.assertEqual(len(many2many1.targets), 1)
+            target1, = many2many1.targets
 
-            datetimes = self.datetime.search([
-                    ('datetime', '=', today),
+            many2manys = many2many.search([
+                    ('targets', '=', 'target1'),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2manys, [many2many1])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '=', tomorrow),
+            many2manys = many2many.search([
+                    ('targets', '!=', 'target1'),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(many2manys, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '=', None),
+            many2manys = many2many.search([
+                    ('targets', 'in', [target1.id]),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(many2manys, [many2many1])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '!=', today),
+            many2manys = many2many.search([
+                    ('targets', 'in', [0]),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(many2manys, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '!=', tomorrow),
+            many2manys = many2many.search([
+                    ('targets', 'not in', [target1.id]),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2manys, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '!=', None),
+            many2manys = many2many.search([
+                    ('targets', 'not in', [0]),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2manys, [many2many1])
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'in', [today]),
+            many2manys = many2many.search([
+                    ('targets.name', '=', 'target1'),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2manys, [many2many1])
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'in', [tomorrow]),
+            many2manys = many2many.search([
+                    ('targets.name', '!=', 'target1'),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(many2manys, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'in', [None]),
+            many2manys = many2many.search([
+                    ('targets', 'where', [('name', '=', 'target1')]),
                     ])
-            self.assertEqual(datetimes, [])
-
-            datetimes = self.datetime.search([
-                    ('datetime', 'in', []),
+            self.assertEqual(many2manys, [many2many1])
+            many2manys = many2many.search([
+                    ('targets', 'not where', [('name', '=', 'target1')]),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(many2manys, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'not in', [today]),
-                    ])
-            self.assertEqual(datetimes, [])
+            many2many2, = many2many.create([{
+                        'name': 'origin2',
+                        }])
+            self.assert_(many2many2)
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'not in', [tomorrow]),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2many2.targets, ())
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'not in', [None]),
+            many2manys = many2many.search([
+                    ('targets', '=', None),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(many2manys, [many2many2])
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'not in', []),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('write', [target1.id], {
+                                'name': 'target1bis',
+                                }),
+                        ],
+                    })
+            self.assertEqual(target1.name, 'target1bis')
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<', tomorrow),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+            target2, = many2many_target.create([{
+                        'name': 'target2',
+                        }])
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('add', [target2.id]),
+                        ],
+                    })
+            self.assertEqual(many2many1.targets,
+                (target1, target2))
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<', yesterday),
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('remove', [target2.id]),
+                        ],
+                    })
+            self.assertEqual(many2many1.targets, (target1,))
+            target2, = many2many_target.search([
+                    ('id', '=', target2.id),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assert_(target2)
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<', today),
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('remove', [target1.id]),
+                        ],
+                    })
+            self.assertEqual(many2many1.targets, ())
+            targets = many2many_target.search([
+                    ('id', 'in', [target1.id, target2.id]),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(targets, [target1, target2])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<=', today),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('add', [target1.id, target2.id]),
+                        ],
+                    })
+            self.assertEqual(many2many1.targets,
+                (target1, target2))
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<=', yesterday),
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('copy', [target1.id], {'name': 'copy1'}),
+                        ],
+                    })
+            targets = many2many_target.search([
+                    ('id', 'not in', [target1.id, target2.id]),
                     ])
-            self.assertEqual(datetimes, [])
+            self.assertEqual(len(targets), 1)
+            self.assertEqual(targets[0].name, 'copy1')
 
-            datetimes = self.datetime.search([
-                    ('datetime', '<=', tomorrow),
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('copy', [target2.id]),
+                        ],
+                    })
+            self.assertEqual(len(many2many1.targets), 4)
+            targets = many2many_target.search([
+                    ('id', 'not in', [target1.id, target2.id]),
+                    ])
+            self.assertEqual(len(targets), 2)
+            names = set([target.name for target in targets])
+            self.assertEqual(names, set(('copy1', 'target2')))
+
+            copy_ids = [target.id for target in targets]
+            many2many.write([many2many1], {
+                    'targets': [
+                        ('delete', [target2.id] + copy_ids),
+                        ],
+                    })
+            self.assertEqual(many2many1.targets, (target1,))
+            targets = many2many_target.search([
+                    ('id', '=', target2.id),
                     ])
-            self.assertEqual(datetimes, [datetime1])
+            self.assertEqual(targets, [])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>', tomorrow),
-                    ])
-            self.assertEqual(datetimes, [])
+            transaction.rollback()
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>', yesterday),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+        self.assertRaises(UserError, Many2manyRequired.create, [{
+                    'name': 'origin3',
+                    }])
+        transaction.rollback()
+
+        origin3_id, = Many2manyRequired.create([{
+                    'name': 'origin3',
+                    'targets': [
+                        ('create', [{
+                                    'name': 'target3',
+                                    }]),
+                        ],
+                    }])
+        self.assert_(origin3_id)
+
+        Many2manySizeTarget.create([{
+                    'name': str(i),
+                    } for i in range(6)])
+
+        transaction.rollback()
+
+    @with_transaction()
+    def test_many2many_tree(self):
+        pool = Pool()
+        Many2Many = pool.get('test.many2many_tree')
+
+        second1, second2, second3, second4 = Many2Many.create([
+                {},
+                {},
+                {},
+                {},
+                ])
+        first1, first2, first3, first4 = Many2Many.create([
+                {'children': [('add', [second1.id, second2.id])]},
+                {'children': [('add', [second1.id, second2.id])]},
+                {'children': [('add', [second3.id, second4.id])]},
+                {'children': [('add', [second4.id])]},
+                ])
+        root1, root2 = Many2Many.create([
+                {'children': [
+                        ('add', [first1.id, first2.id, second1.id])]},
+                {'children': [('add', [first3.id, first4.id])]},
+                ])
+
+        all_ = Many2Many.search([])
+
+        def not_(l):
+            return [r for r in all_ if r not in l]
+
+        for clause, test in [
+                ([root1.id], [second1, second2, first1, first2, root1]),
+                ([second1.id], [second1]),
+                ([root2.id], [second3, second4, first3, first4, root2]),
+                ([], []),
+                ]:
+            result = Many2Many.search(
+                [('parents', 'child_of', clause)])
+            self.assertEqual(result, test)
+
+            result = Many2Many.search(
+                [('parents', 'not child_of', clause)])
+            self.assertEqual(result, not_(test))
+
+        for clause, test in [
+                ([root1.id], [root1]),
+                ([first3.id], [first3, root2]),
+                ([second4.id], [second4, first3, first4, root2]),
+                ([second4.id, first4.id], [second4, first3, first4,
+                        root2]),
+                ([], []),
+                ]:
+            result = Many2Many.search(
+                [('parents', 'parent_of', clause)])
+            self.assertEqual(result, test)
+
+            result = Many2Many.search(
+                [('parents', 'not parent_of', clause)])
+            self.assertEqual(result, not_(test))
+
+    @with_transaction()
+    def test_reference(self):
+        'Test Reference'
+        pool = Pool()
+        Reference = pool.get('test.reference')
+        ReferenceTarget = pool.get('test.reference.target')
+        ReferenceRequired = pool.get('test.reference_required')
+        transaction = Transaction()
+
+        target1, = ReferenceTarget.create([{
+                    'name': 'target1',
+                    }])
+        reference1, = Reference.create([{
+                    'name': 'reference1',
+                    'reference': str(target1),
+                    }])
+        self.assert_(reference1)
+
+        self.assertEqual(reference1.reference, target1)
+
+        references = Reference.search([
+                ('reference', '=', str(target1)),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference', '=', (target1.__name__, target1.id)),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference', '=', [target1.__name__, target1.id]),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference.name', '=', 'target1',
+                    'test.reference.target'),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference', '!=', str(target1)),
+                ])
+        self.assertEqual(references, [])
+
+        references = Reference.search([
+                ('reference', '!=', str(target1)),
+                ])
+        self.assertEqual(references, [])
+
+        references = Reference.search([
+                ('reference', 'in', [str(target1)]),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference', 'in',
+                    [('test.reference.target', target1.id)]),
+                ])
+        self.assertEqual(references, [reference1])
+
+        references = Reference.search([
+                ('reference', 'in', [None]),
+                ])
+        self.assertEqual(references, [])
+
+        references = Reference.search([
+                ('reference', 'not in', [str(target1)]),
+                ])
+        self.assertEqual(references, [])
+
+        references = Reference.search([
+                ('reference', 'not in',
+                    [('test.reference.target', target1.id)]),
+                ])
+        self.assertEqual(references, [])
+
+        references = Reference.search([
+                ('reference', 'not in', [None]),
+                ])
+        self.assertEqual(references, [reference1])
+
+        reference2, = Reference.create([{
+                    'name': 'reference2',
+                    }])
+        self.assert_(reference2)
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>', today),
-                    ])
-            self.assertEqual(datetimes, [])
+        self.assertEqual(reference2.reference, None)
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>=', tomorrow),
-                    ])
-            self.assertEqual(datetimes, [])
+        references = Reference.search([
+                ('reference', '=', None),
+                ])
+        self.assertEqual(references, [reference2])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>=', yesterday),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+        target2, = ReferenceTarget.create([{
+                    'name': 'target2',
+                    }])
 
-            datetimes = self.datetime.search([
-                    ('datetime', '>=', today),
-                    ])
-            self.assertEqual(datetimes, [datetime1])
+        Reference.write([reference2], {
+                'reference': str(target2),
+                })
+        self.assertEqual(reference2.reference, target2)
 
-            datetime2, = self.datetime.create([{
-                        'datetime': yesterday,
-                        }])
-            self.assert_(datetime2)
-            self.assertEqual(datetime2.datetime, yesterday)
+        Reference.write([reference2], {
+                'reference': None,
+                })
+        self.assertEqual(reference2.reference, None)
 
-            datetimes = self.datetime.search([
-                    ('datetime', '=', yesterday),
-                    ])
-            self.assertEqual(datetimes, [datetime2])
+        Reference.write([reference2], {
+                'reference': ('test.reference.target', target2.id),
+                })
+        self.assertEqual(reference2.reference, target2)
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'in', [yesterday, today]),
-                    ])
-            self.assertEqual(datetimes, [datetime1, datetime2])
+        reference3, = Reference.create([{
+                    'name': 'reference3',
+                    'reference': ('test.reference.target', target1.id),
+                    }])
+        self.assert_(reference3)
 
-            datetimes = self.datetime.search([
-                    ('datetime', 'not in', [yesterday, today]),
-                    ])
-            self.assertEqual(datetimes, [])
+        self.assertRaises(UserError, ReferenceRequired.create, [{
+                    'name': 'reference4',
+                    }])
+        transaction.rollback()
 
-            datetime3, = self.datetime.create([{}])
-            self.assert_(datetime3)
-            self.assertEqual(datetime3.datetime, None)
+        target4, = ReferenceTarget.create([{
+                    'name': 'target4_id',
+                    }])
 
-            datetime4, = self.datetime_default.create([{}])
-            self.assert_(datetime4)
-            self.assertEqual(datetime4.datetime, default_datetime)
+        reference4, = ReferenceRequired.create([{
+                    'name': 'reference4',
+                    'reference': str(target4),
+                    }])
+        self.assert_(reference4)
 
-            self.datetime.write([datetime1], {
-                    'datetime': yesterday,
-                    })
-            self.assertEqual(datetime1.datetime, yesterday)
+    @with_transaction()
+    def test_property(self):
+        'Test Property with supported field types'
+        pool = Pool()
+        Property = pool.get('test.property')
+        IrProperty = pool.get('ir.property')
+        ModelField = pool.get('ir.model.field')
+        Char = pool.get('test.char')
+        transaction = Transaction()
 
-            self.datetime.write([datetime2], {
-                    'datetime': today,
-                    })
-            self.assertEqual(datetime2.datetime, today)
+        # Test Char
+        prop_a, = Property.create([{'char': 'Test'}])
+        self.assert_(prop_a)
+        self.assertEqual(prop_a.char, 'Test')
 
-            self.assertRaises(Exception, self.datetime.create, [{
-                        'datetime': 'test',
-                        }])
+        prop_b, = Property.create([{}])
+        self.assert_(prop_b)
+        self.assertEqual(prop_b.char, None)
 
-            self.assertRaises(Exception, self.datetime.write, [datetime1],
-                {
-                    'datetime': 'test',
-                    })
+        prop_c, = Property.create([{'char': 'FooBar'}])
+        self.assert_(prop_c)
+        self.assertEqual(prop_c.char, 'FooBar')
 
-            self.assertRaises(Exception, self.datetime.create, [{
-                        'datetime': 1,
-                        }])
+        props = Property.search([('char', '=', 'Test')])
+        self.assertEqual(props, [prop_a])
 
-            self.assertRaises(Exception, self.datetime.write, [datetime1],
-                {
-                    'datetime': 1,
-                    })
+        props = Property.search([('char', '=', None)])
+        self.assertEqual(props, [prop_b])
 
-            self.assertRaises(Exception, self.datetime.create, [{
-                        'datetime': datetime.date.today(),
-                        }])
+        props = Property.search([('char', '!=', None)])
+        self.assertEqual(props, [prop_a, prop_c])
 
-            self.assertRaises(Exception, self.datetime.write, [datetime1],
-                {
-                    'datetime': datetime.date.today(),
-                    })
+        props = Property.search([('char', 'like', 'Tes%')])
+        self.assertEqual(props, [prop_a])
 
-            self.assertRaises(Exception, self.datetime.create, [{
-                        'datetime': '2009-13-01 12:30:00',
-                        }])
+        props = Property.search([('char', 'like', '%Bar')])
+        self.assertEqual(props, [prop_c])
 
-            self.assertRaises(Exception, self.datetime.write, [datetime1],
-                {
-                    'datetime': '2009-02-29 12:30:00',
-                    })
+        props = Property.search([('char', 'not like', 'Tes%')])
+        self.assertEqual(props, [prop_b, prop_c])
 
-            self.assertRaises(Exception, self.datetime.write, [datetime1],
-                {
-                    'datetime': '2009-01-01 25:00:00',
-                    })
+        props = Property.search([('char', 'ilike', 'tes%')])
+        self.assert_(props, [prop_a])
 
-            datetime5, = self.datetime.create([{
-                    'datetime': '2009-01-01 12:00:00',
-                    }])
-            self.assert_(datetime5)
-            self.assertEqual(datetime5.datetime,
-                datetime.datetime(2009, 1, 1, 12, 0, 0))
+        props = Property.search([('char', 'ilike', '%bar')])
+        self.assertEqual(props, [prop_c])
 
-            self.assertRaises(UserError, self.datetime_required.create, [{}])
-            transaction.cursor.rollback()
+        props = Property.search([('char', 'not ilike', 'tes%')])
+        self.assertEqual(props, [prop_b, prop_c])
 
-            datetime6, = self.datetime_required.create([{
-                        'datetime': today,
-                        }])
-            self.assert_(datetime6)
+        props = Property.search([('char', 'in', ['Test'])])
+        self.assertEqual(props, [prop_a])
 
-            datetime7, = self.datetime.create([{
-                        'datetime': None,
-                        }])
-            self.assert_(datetime7)
+        props = Property.search([
+                ('char', 'in', ['Test', 'FooBar'])])
+        self.assertEqual(props, [prop_a, prop_c])
 
-            datetime8, = self.datetime.create([{
-                        'datetime': None,
-                        }])
-            self.assert_(datetime8)
+        props = Property.search([
+                ('char', 'not in', ['Test', 'FooBar'])])
+        self.assertEqual(props, [prop_b])
 
-            datetime9, = self.datetime.create([{
-                        'datetime': today.replace(microsecond=1),
-                        }])
-            self.assert_(datetime9)
-            self.assertEqual(datetime9.datetime, today)
-
-            # Test format
-            self.assert_(self.datetime_format.create([{
-                            'datetime': datetime.datetime(2009, 1, 1, 12, 30),
-                            }]))
-            self.assertRaises(UserError, self.datetime_format.create, [{
-                        'datetime': datetime.datetime(2009, 1, 1, 12, 30, 25),
-                        }])
+        # Test default value
+        property_field, = ModelField.search([
+                ('model.model', '=', 'test.property'),
+                ('name', '=', 'char'),
+                ], limit=1)
+        IrProperty.create([{
+                    'field': property_field.id,
+                    'value': ',DEFAULT_VALUE',
+                    }])
 
-            transaction.cursor.rollback()
+        prop_d, = Property.create([{}])
+        self.assert_(prop_d)
+        self.assertEqual(prop_d.char, 'DEFAULT_VALUE')
 
-    def test0100time(self):
-        'Test Time'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            pre_evening = datetime.time(16, 30)
-            evening = datetime.time(18, 45, 3)
-            night = datetime.time(20, 00)
-            default_time = datetime.time(16, 30)
-
-            time1, = self.time.create([{
-                        'time': evening,
-                        }])
-            self.assert_(time1)
-            self.assertEqual(time1.time, evening)
+        props = Property.search([('char', '!=', None)])
+        self.assertEqual(props, [prop_a, prop_c, prop_d])
 
-            times = self.time.search([
-                    ('time', '=', evening),
-                    ])
-            self.assertEqual(times, [time1])
+        Property.write([prop_a], {'char': None})
+        self.assertEqual(prop_a.char, None)
 
-            times = self.time.search([
-                    ('time', '=', night),
-                    ])
-            self.assertEqual(times, [])
+        Property.write([prop_b], {'char': 'Test'})
+        self.assertEqual(prop_b.char, 'Test')
 
-            times = self.time.search([
-                    ('time', '=', None),
-                    ])
-            self.assertEqual(times, [])
+        transaction.rollback()
 
-            times = self.time.search([
-                    ('time', '!=', evening),
-                    ])
-            self.assertEqual(times, [])
+        # Test Many2One
+        char_a, = Char.create([{'char': 'Test'}])
+        self.assert_(char_a)
 
-            times = self.time.search([
-                    ('time', '!=', night),
-                    ])
-            self.assertEqual(times, [time1])
+        char_b, = Char.create([{'char': 'FooBar'}])
+        self.assert_(char_b)
 
-            times = self.time.search([
-                    ('time', '!=', None),
-                    ])
-            self.assertEqual(times, [time1])
+        prop_a, = Property.create([{'many2one': char_a.id}])
+        self.assert_(prop_a)
+        self.assertEqual(prop_a.many2one, char_a)
 
-            times = self.time.search([
-                    ('time', 'in', [evening]),
-                    ])
-            self.assertEqual(times, [time1])
+        prop_b, = Property.create([{'many2one': char_b.id}])
+        self.assert_(prop_b)
+        self.assertEqual(prop_b.many2one, char_b)
 
-            times = self.time.search([
-                    ('time', 'in', [night]),
-                    ])
-            self.assertEqual(times, [])
+        prop_c, = Property.create([{}])
+        self.assert_(prop_c)
+        self.assertEqual(prop_c.many2one, None)
 
-            times = self.time.search([
-                    ('time', 'in', [None]),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([('many2one', '=', char_a.id)])
+        self.assertEqual(props, [prop_a])
 
-            times = self.time.search([
-                    ('time', 'in', []),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([('many2one', '!=', None)])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', 'not in', [evening]),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([('many2one', '=', None)])
+        self.assertEqual(props, [prop_c])
 
-            times = self.time.search([
-                    ('time', 'not in', [night]),
-                    ])
-            self.assertEqual(times, [time1])
+        self.assertEqual(prop_a.many2one, char_a)
 
-            times = self.time.search([
-                    ('time', 'not in', [None]),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([
+                ('many2one', 'in', [char_a.id, char_b.id])])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', 'not in', []),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([
+                ('many2one', 'not in', [char_a.id, char_b.id])])
+        self.assertEqual(props, [prop_c])
 
-            times = self.time.search([
-                    ('time', '<', night),
-                    ])
-            self.assertEqual(times, [time1])
+        Property.write([prop_b], {'many2one': char_a.id})
+        self.assertEqual(prop_b.many2one, char_a)
 
-            times = self.time.search([
-                    ('time', '<', pre_evening),
-                    ])
-            self.assertEqual(times, [])
+        transaction.rollback()
 
-            times = self.time.search([
-                    ('time', '<', evening),
-                    ])
-            self.assertEqual(times, [])
+        # Test Numeric
+        prop_a, = Property.create([{'numeric': Decimal('1.1')}])
+        self.assert_(prop_a)
+        self.assertEqual(prop_a.numeric, Decimal('1.1'))
 
-            times = self.time.search([
-                    ('time', '<=', evening),
-                    ])
-            self.assertEqual(times, [time1])
+        prop_b, = Property.create([{'numeric': Decimal('2.6')}])
+        self.assert_(prop_b)
+        self.assertEqual(prop_b.numeric, Decimal('2.6'))
 
-            times = self.time.search([
-                    ('time', '<=', pre_evening),
-                    ])
-            self.assertEqual(times, [])
+        prop_c, = Property.create([{}])
+        self.assert_(prop_c)
+        self.assertEqual(prop_c.numeric, None)
 
-            times = self.time.search([
-                    ('time', '<=', night),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([('numeric', '!=', None)])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', '>', night),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([('numeric', '=', None)])
+        self.assertEqual(props, [prop_c])
 
-            times = self.time.search([
-                    ('time', '>', pre_evening),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([
+                ('numeric', '=', Decimal('1.1')),
+                ])
+        self.assertEqual(props, [prop_a])
 
-            times = self.time.search([
-                    ('time', '>', evening),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([
+                ('numeric', '!=', Decimal('1.1'))])
+        self.assertEqual(props, [prop_b, prop_c])
 
-            times = self.time.search([
-                    ('time', '>=', night),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([
+                ('numeric', '<', Decimal('2.6')),
+                ])
+        self.assertEqual(props, [prop_a])
 
-            times = self.time.search([
-                    ('time', '>=', pre_evening),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([
+                ('numeric', '<=', Decimal('2.6'))])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', '>=', evening),
-                    ])
-            self.assertEqual(times, [time1])
+        props = Property.search([
+                ('numeric', '>', Decimal('1.1')),
+                ])
+        self.assertEqual(props, [prop_b])
 
-            time2, = self.time.create([{
-                        'time': pre_evening,
-                        }])
-            self.assert_(time2)
-            self.assertEqual(time2.time, pre_evening)
+        props = Property.search([
+                ('numeric', '>=', Decimal('1.1'))])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', '=', pre_evening),
-                    ])
-            self.assertEqual(times, [time2])
+        props = Property.search([
+                ('numeric', 'in', [Decimal('1.1')])])
+        self.assertEqual(props, [prop_a])
 
-            times = self.time.search([
-                    ('time', 'in', [pre_evening, evening]),
-                    ])
-            self.assertEqual(times, [time1, time2])
+        props = Property.search([
+                ('numeric', 'in', [Decimal('1.1'), Decimal('2.6')])])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            times = self.time.search([
-                    ('time', 'not in', [pre_evening, evening]),
-                    ])
-            self.assertEqual(times, [])
+        props = Property.search([
+                ('numeric', 'not in', [Decimal('1.1')])])
+        self.assertEqual(props, [prop_b, prop_c])
 
-            time3, = self.time.create([{}])
-            self.assert_(time3)
-            self.assertEqual(time3.time, None)
+        props = Property.search([
+                ('numeric', 'not in', [Decimal('1.1'), Decimal('2.6')])])
+        self.assertEqual(props, [prop_c])
 
-            time4, = self.time_default.create([{}])
-            self.assert_(time4)
-            self.assertEqual(time4.time, default_time)
+        # Test default value
+        property_field, = ModelField.search([
+                ('model.model', '=', 'test.property'),
+                ('name', '=', 'numeric'),
+                ], limit=1)
+        IrProperty.create([{
+                    'field': property_field.id,
+                    'value': ',3.7',
+                    }])
 
-            self.time.write([time1], {
-                    'time': pre_evening,
-                    })
-            self.assertEqual(time1.time, pre_evening)
+        prop_d, = Property.create([{}])
+        self.assert_(prop_d)
+        self.assertEqual(prop_d.numeric, Decimal('3.7'))
 
-            self.time.write([time2], {
-                    'time': evening,
-                    })
-            self.assertEqual(time2.time, evening)
+        Property.write([prop_a], {'numeric': None})
+        self.assertEqual(prop_a.numeric, None)
 
-            self.assertRaises(Exception, self.time.create, [{
-                        'time': 'test',
-                        }])
+        Property.write([prop_b], {'numeric': Decimal('3.11')})
+        self.assertEqual(prop_b.numeric, Decimal('3.11'))
 
-            self.assertRaises(Exception, self.time.write, [time1],
-                {
-                    'time': 'test',
-                    })
+        transaction.rollback()
 
-            self.assertRaises(Exception, self.time.create, [{
-                    'time': 1,
-                    }])
+        # Test Selection
+        prop_a, = Property.create([{'selection': 'option_a'}])
+        self.assert_(prop_a)
+        self.assertEqual(prop_a.selection, 'option_a')
 
-            self.assertRaises(Exception, self.time.write, [time1],
-                {
-                    'time': 1,
-                    })
+        prop_b, = Property.create([{'selection': 'option_b'}])
+        self.assert_(prop_b)
+        self.assertEqual(prop_b.selection, 'option_b')
 
-            self.assertRaises(Exception, self.time.write, [time1],
-                {
-                    'time': '25:00:00',
-                    })
+        prop_c, = Property.create([{}])
+        self.assert_(prop_c)
+        self.assertEqual(prop_c.selection, None)
 
-            time5, = self.time.create([{
-                        'time': '12:00:00',
-                        }])
-            self.assert_(time5)
-            self.assertEqual(time5.time, datetime.time(12, 0))
+        props = Property.search([('selection', '=', 'option_a')])
+        self.assertEqual(props, [prop_a])
 
-            self.assertRaises(UserError, self.time_required.create, [{}])
-            transaction.cursor.rollback()
+        props = Property.search([('selection', '!=', None)])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            time6, = self.time_required.create([{
-                        'time': evening,
-                        }])
-            self.assert_(time6)
+        props = Property.search([('selection', '=', None)])
+        self.assertEqual(props, [prop_c])
 
-            time7, = self.time.create([{
-                        'time': None,
-                        }])
-            self.assert_(time7)
+        props = Property.search([('selection', '!=', 'option_a')])
+        self.assertEqual(props, [prop_b, prop_c])
 
-            time9, = self.time.create([{
-                        'time': evening.replace(microsecond=1),
-                        }])
-            self.assert_(time9)
-            self.assertEqual(time9.time, evening)
+        props = Property.search([
+                ('selection', 'in', ['option_a'])])
+        self.assertEqual(props, [prop_a])
 
-            # Test format
-            self.assert_(self.time_format.create([{
-                        'time': datetime.time(12, 30),
-                        }]))
-            self.assertRaises(UserError, self.time_format.create, [{
-                    'time': datetime.time(12, 30, 25),
-                    }])
+        props = Property.search([
+                ('selection', 'in', ['option_a', 'option_b'])])
+        self.assertEqual(props, [prop_a, prop_b])
 
-            transaction.cursor.rollback()
+        props = Property.search([
+                ('selection', 'not in', ['option_a'])])
+        self.assertEqual(props, [prop_b, prop_c])
 
-    def test0110one2one(self):
-        'Test One2One'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            target1, = self.one2one_target.create([{
-                        'name': 'target1',
-                        }])
-            one2one1, = self.one2one.create([{
-                        'name': 'origin1',
-                        'one2one': target1.id,
-                        }])
-            self.assert_(one2one1)
-            self.assertEqual(one2one1.one2one, target1)
+        # Test default value
+        property_field, = ModelField.search([
+                ('model.model', '=', 'test.property'),
+                ('name', '=', 'selection'),
+                ], limit=1)
+        IrProperty.create([{
+                    'field': property_field.id,
+                    'value': ',option_a',
+                    }])
 
-            self.assertEqual(self.one2one.read([one2one1.id],
-                    ['one2one.name'])[0]['one2one.name'], 'target1')
+        prop_d, = Property.create([{}])
+        self.assert_(prop_d)
+        self.assertEqual(prop_d.selection, 'option_a')
 
-            one2ones = self.one2one.search([
-                    ('one2one', '=', 'target1'),
-                    ])
-            self.assertEqual(one2ones, [one2one1])
+        Property.write([prop_a], {'selection': None})
+        self.assertEqual(prop_a.selection, None)
 
-            one2ones = self.one2one.search([
-                    ('one2one', '!=', 'target1'),
-                    ])
-            self.assertEqual(one2ones, [])
+        Property.write([prop_c], {'selection': 'option_b'})
+        self.assertEqual(prop_c.selection, 'option_b')
 
-            one2ones = self.one2one.search([
-                    ('one2one', 'in', [target1.id]),
-                    ])
-            self.assertEqual(one2ones, [one2one1])
+    @with_transaction()
+    def test_selection(self):
+        'Test Selection'
+        pool = Pool()
+        Selection = pool.get('test.selection')
+        SelectionRequired = pool.get('test.selection_required')
+        transaction = Transaction()
+
+        selection1, = Selection.create([{'select': 'arabic'}])
+        self.assert_(selection1)
+        self.assertEqual(selection1.select, 'arabic')
+        self.assertEqual(selection1.select_string, 'Arabic')
+
+        selection2, = Selection.create([{'select': None}])
+        self.assert_(selection2)
+        self.assertEqual(selection2.select, None)
+        self.assertEqual(selection2.select_string, '')
+
+        self.assertRaises(UserError, Selection.create,
+            [{'select': 'chinese'}])
+
+        selection3, = Selection.create(
+            [{'select': 'arabic', 'dyn_select': '1'}])
+        self.assert_(selection3)
+        self.assertEqual(selection3.select, 'arabic')
+        self.assertEqual(selection3.dyn_select, '1')
+
+        selection4, = Selection.create(
+            [{'select': 'hexa', 'dyn_select': '0x3'}])
+        self.assert_(selection4)
+        self.assertEqual(selection4.select, 'hexa')
+        self.assertEqual(selection4.dyn_select, '0x3')
+
+        selection5, = Selection.create(
+            [{'select': 'hexa', 'dyn_select': None}])
+        self.assert_(selection5)
+        self.assertEqual(selection5.select, 'hexa')
+        self.assertEqual(selection5.dyn_select, None)
+
+        self.assertRaises(UserError, Selection.create,
+            [{'select': 'arabic', 'dyn_select': '0x3'}])
+        self.assertRaises(UserError, Selection.create,
+            [{'select': 'hexa', 'dyn_select': '3'}])
+
+        self.assertRaises(UserError, SelectionRequired.create, [{}])
+        transaction.rollback()
+
+        self.assertRaises(UserError, SelectionRequired.create,
+            [{'select': None}])
+        transaction.rollback()
+
+        selection6, = SelectionRequired.create([{'select': 'latin'}])
+        self.assert_(selection6)
+        self.assertEqual(selection6.select, 'latin')
+
+    @with_transaction()
+    def test_dict(self):
+        'Test Dict'
+        pool = Pool()
+        Dict = pool.get('test.dict')
+        DictSchema = pool.get('test.dict.schema')
+        DictDefault = pool.get('test.dict_default')
+        DictRequired = pool.get('test.dict_required')
+        transaction = Transaction()
+
+        DictSchema.create([{
+                    'name': 'a',
+                    'string': 'A',
+                    'type_': 'integer',
+                    }, {
+                    'name': 'b',
+                    'string': 'B',
+                    'type_': 'integer',
+                    }, {
+                    'name': 'type',
+                    'string': 'Type',
+                    'type_': 'selection',
+                    'selection': ('arabic: Arabic\n'
+                        'hexa: Hexadecimal'),
+                    }])
 
-            one2ones = self.one2one.search([
-                    ('one2one', 'in', [0]),
-                    ])
-            self.assertEqual(one2ones, [])
+        dict1, = Dict.create([{
+                    'dico': {'a': 1, 'b': 2},
+                    }])
+        self.assert_(dict1.dico == {'a': 1, 'b': 2})
+
+        Dict.write([dict1], {'dico': {'z': 26}})
+        self.assert_(dict1.dico == {'z': 26})
+
+        dict1.dico = {
+            'a': 1,
+            'type': 'arabic',
+            }
+        dict1.save()
+        self.assertEqual(dict1.dico, {'a': 1, 'type': 'arabic'})
+        self.assertEqual(dict1.dico_string, {
+                'a': 1,
+                'type': 'Arabic',
+                })
+        self.assertEqual(dict1.dico_string_keys, {
+                'a': 'A',
+                'type': 'Type',
+                })
 
-            one2ones = self.one2one.search([
-                    ('one2one', 'not in', [target1.id]),
-                    ])
-            self.assertEqual(one2ones, [])
+        dict2, = Dict.create([{}])
+        self.assert_(dict2.dico is None)
 
-            one2ones = self.one2one.search([
-                    ('one2one', 'not in', [0]),
-                    ])
-            self.assertEqual(one2ones, [one2one1])
+        dict3, = DictDefault.create([{}])
+        self.assert_(dict3.dico == {'a': 1})
 
-            one2ones = self.one2one.search([
-                    ('one2one.name', '=', 'target1'),
-                    ])
-            self.assertEqual(one2ones, [one2one1])
+        self.assertRaises(UserError, DictRequired.create, [{}])
+        transaction.rollback()
 
-            one2ones = self.one2one.search([
-                    ('one2one.name', '!=', 'target1'),
-                    ])
-            self.assertEqual(one2ones, [])
+        dict4, = DictRequired.create([{'dico': dict(a=1)}])
+        self.assert_(dict4.dico == {'a': 1})
 
-            one2one2, = self.one2one.create([{
-                        'name': 'origin2',
-                        }])
-            self.assert_(one2one2)
-            self.assertEqual(one2one2.one2one, None)
+        self.assertRaises(UserError, DictRequired.create,
+            [{'dico': {}}])
 
-            one2ones = self.one2one.search([
-                    ('one2one', '=', None),
-                    ])
-            self.assertEqual(one2ones, [one2one2])
+    @with_transaction()
+    def test_binary(self):
+        'Test Binary'
+        pool = Pool()
+        Binary = pool.get('test.binary')
+        BinaryDefault = pool.get('test.binary_default')
+        BinaryRequired = pool.get('test.binary_required')
+        transaction = Transaction()
+
+        bin1, = Binary.create([{
+                    'binary': fields.Binary.cast(b'foo'),
+                    }])
+        self.assert_(bin1.binary == fields.Binary.cast(b'foo'))
 
-            target2, = self.one2one_target.create([{
-                        'name': 'target2',
-                        }])
-            self.one2one.write([one2one2], {
-                    'one2one': target2.id,
-                    })
-            self.assertEqual(one2one2.one2one, target2)
+        Binary.write([bin1], {'binary': fields.Binary.cast(b'bar')})
+        self.assert_(bin1.binary == fields.Binary.cast(b'bar'))
 
-            self.one2one.write([one2one2], {
-                    'one2one': None,
-                    })
-            self.assertEqual(one2one2.one2one, None)
+        with transaction.set_context({'test.binary.binary': 'size'}):
+            bin1_size = Binary(bin1.id)
+            self.assert_(bin1_size.binary == len(b'bar'))
+            self.assert_(bin1_size.binary != fields.Binary.cast(b'bar'))
 
-            self.assertRaises(UserError, self.one2one.create, [{
-                        'name': 'one2one3',
-                        'one2one': target1.id,
-                        }])
-            transaction.cursor.rollback()
+        bin2, = Binary.create([{}])
+        self.assert_(bin2.binary is None)
 
-            self.assertRaises(UserError, self.one2one.write, [one2one2], {
-                    'one2one': target1.id,
-                    })
-            transaction.cursor.rollback()
+        bin3, = BinaryDefault.create([{}])
+        self.assert_(bin3.binary == fields.Binary.cast(b'default'))
 
-            self.assertRaises(UserError, self.one2one_required.create, [{
-                        'name': 'one2one3',
-                        }])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, BinaryRequired.create, [{}])
+        transaction.rollback()
 
-            target3, = self.one2one_target.create([{
-                        'name': 'target3',
-                        }])
+        bin4, = BinaryRequired.create([{
+                    'binary': fields.Binary.cast(b'baz'),
+                    }])
+        self.assert_(bin4.binary == fields.Binary.cast(b'baz'))
 
-            one2one3, = self.one2one_required.create([{
-                        'name': 'one2one3',
-                        'one2one': target3.id,
-                        }])
-            self.assert_(one2one3)
+        self.assertRaises(UserError, BinaryRequired.create,
+            [{'binary': fields.Binary.cast(b'')}])
 
-            target4, = self.one2one_target.create([{
-                        'name': 'target4',
-                        }])
-            self.assertRaises(UserError, self.one2one_domain.create, [{
-                        'name': 'one2one4',
-                        'one2one': target4.id,
-                        }])
-            transaction.cursor.rollback()
+    @with_transaction()
+    def test_many2one(self):
+        'Test Many2One'
+        pool = Pool()
+        Many2oneDomainValidation = pool.get('test.many2one_domainvalidation')
+        Many2oneOrderby = pool.get('test.many2one_orderby')
+        Many2oneTarget = pool.get('test.many2one_target')
+        Many2oneSearch = pool.get('test.many2one_search')
+        transaction = Transaction()
+
+        # Not respecting the domain raise an Error
+        m2o_1, = Many2oneTarget.create([{'value': 1}])
+        self.assertRaises(UserError, Many2oneDomainValidation.create,
+            [{'many2one': m2o_1}])
+
+        # Respecting the domain works
+        m2o_6, = Many2oneTarget.create([{'value': 6}])
+        domain, = Many2oneDomainValidation.create([{'many2one': m2o_6}])
+        self.assert_(domain)
+        self.assertEqual(domain.many2one.value, 6)
+
+        # Inactive records are taken into account
+        m2o_6.active = False
+        m2o_6.save()
+        domain.dummy = 'Dummy'
+        domain.save()
+
+        # Testing order_by
+        for value in (5, 3, 2):
+            m2o, = Many2oneTarget.create([{'value': value}])
+            Many2oneOrderby.create([{'many2one': m2o}])
+
+        search = Many2oneOrderby.search([], order=[('many2one', 'ASC')])
+        self.assertTrue(all(x.many2one.value <= y.many2one.value
+                for x, y in zip(search, search[1:])))
+
+        search = Many2oneOrderby.search([],
+            order=[('many2one.id', 'ASC')])
+        self.assertTrue(all(x.many2one.id <= y.many2one.id
+                for x, y in zip(search, search[1:])))
+
+        search = Many2oneOrderby.search([],
+            order=[('many2one.value', 'ASC')])
+        self.assertTrue(all(x.many2one.value <= y.many2one.value
+                for x, y in zip(search, search[1:])))
+
+        transaction.rollback()
+
+        target1, target2 = Many2oneTarget.create([
+                {'value': 1},
+                {'value': 2},
+                ])
+
+        search1, search2 = Many2oneSearch.create([
+                {'many2one': target1.id},
+                {'many2one': target2.id},
+                ])
+
+        # Search join
+        Many2oneSearch.target_search = 'join'
+        self.assertEqual(Many2oneSearch.search([
+                    ('many2one.value', '=', 1),
+                    ]), [search1])
+
+        # Search subquery
+        Many2oneSearch.target_search = 'subquery'
+        self.assertEqual(Many2oneSearch.search([
+                    ('many2one.value', '=', 1),
+                    ]), [search1])
+
+        transaction.rollback()
+
+        for model in ['test.many2one_tree', 'test.many2one_mptt']:
+            pool = Pool()
+            Many2One = pool.get(model)
+
+            root1, root2 = Many2One.create([{}, {}])
+            first1, first2, first3, first4 = Many2One.create([
+                    {'many2one': root1.id},
+                    {'many2one': root1.id},
+                    {'many2one': root2.id},
+                    {'many2one': root2.id},
+                    ])
+            second1, second2, second3, second4 = Many2One.create([
+                    {'many2one': first1.id},
+                    {'many2one': first1.id},
+                    {'many2one': first2.id},
+                    {'many2one': first2.id},
+                    ])
+            all_ = Many2One.search([])
+
+            def not_(l):
+                return [r for r in all_ if r not in l]
+
+            for clause, test in [
+                    ([root1.id], [root1, first1, first2,
+                            second1, second2, second3, second4]),
+                    ([second1.id], [second1]),
+                    ([root2.id], [root2, first3, first4]),
+                    ([first2.id, first3.id], [first2, first3,
+                            second3, second4]),
+                    ([], []),
+                    ]:
+                result = Many2One.search(
+                    [('many2one', 'child_of', clause)])
+                self.assertEqual(result, test)
+
+                result = Many2One.search(
+                    [('many2one', 'not child_of', clause)])
+                self.assertEqual(result, not_(test))
+
+            for clause, test in [
+                    ([root1.id], [root1]),
+                    ([first3.id], [root2, first3]),
+                    ([second4.id], [root1, first2, second4]),
+                    ([second4.id, first4.id], [root1, root2,
+                            first2, first4, second4]),
+                    ([], []),
+                    ]:
+                result = Many2One.search(
+                    [('many2one', 'parent_of', clause)])
+                self.assertEqual(result, test)
+
+                result = Many2One.search(
+                    [('many2one', 'not parent_of', clause)])
+                self.assertEqual(result, not_(test))
+
+            transaction.rollback()
+
+    @with_transaction()
+    def test_timedelta(self):
+        'Test timedelta'
+        pool = Pool()
+        Timedelta = pool.get('test.timedelta')
+        TimedeltaDefault = pool.get('test.timedelta_default')
+        TimedeltaRequired = pool.get('test.timedelta_required')
+        transaction = Transaction()
+
+        minute = datetime.timedelta(minutes=1)
+        hour = datetime.timedelta(hours=1)
+        day = datetime.timedelta(days=1)
+        default_timedelta = datetime.timedelta(seconds=3600)
+
+        timedelta1, = Timedelta.create([{
+                    'timedelta': hour,
+                    }])
+        self.assert_(timedelta1)
+        self.assertEqual(timedelta1.timedelta, hour)
+
+        timedelta = Timedelta.search([
+                ('timedelta', '=', hour),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '=', day),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '=', None),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '!=', day),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '!=', None),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', [hour]),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', [day]),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', [minute]),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', [None]),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', []),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'not in', [hour]),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'not in', [day]),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'not in', [None]),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'not in', []),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<', day),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<', minute),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<', hour),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<=', hour),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<=', minute),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '<=', day),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>', day),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>', minute),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>', hour),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>=', day),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>=', minute),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta = Timedelta.search([
+                ('timedelta', '>=', hour),
+                ])
+        self.assertEqual(timedelta, [timedelta1])
+
+        timedelta2, = Timedelta.create([{
+                    'timedelta': minute,
+                    }])
+        self.assert_(timedelta2)
+        self.assertEqual(timedelta2.timedelta, minute)
+
+        timedelta = Timedelta.search([
+                ('timedelta', '=', minute),
+                ])
+        self.assertEqual(timedelta, [timedelta2])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'in', [minute, hour]),
+                ])
+        self.assertEqual(timedelta, [timedelta1, timedelta2])
+
+        timedelta = Timedelta.search([
+                ('timedelta', 'not in', [minute, hour]),
+                ])
+        self.assertEqual(timedelta, [])
+
+        timedelta3, = Timedelta.create([{}])
+        self.assert_(timedelta3)
+        self.assertEqual(timedelta3.timedelta, None)
+
+        timedelta4, = TimedeltaDefault.create([{}])
+        self.assert_(timedelta4)
+        self.assertEqual(timedelta4.timedelta, default_timedelta)
+
+        Timedelta.write([timedelta1], {
+                'timedelta': minute,
+                })
+        self.assertEqual(timedelta1.timedelta, minute)
+
+        Timedelta.write([timedelta2], {
+                'timedelta': day,
+                })
+        self.assertEqual(timedelta2.timedelta, day)
+
+        self.assertRaises(Exception, Timedelta.create, [{
+                    'timedelta': 'test',
+                    }])
 
-            target5, = self.one2one_target.create([{
-                        'name': 'domain',
-                        }])
-            one2one5, = self.one2one_domain.create([{
-                        'name': 'one2one5',
-                        'one2one': target5.id,
-                        }])
-            targets = self.one2one_target.create([{
-                        'name': 'multiple1',
-                        }, {
-                        'name': 'multiple2',
-                        }])
-            one2ones = self.one2one.create([{
-                        'name': 'origin6',
-                        'one2one': targets[0].id,
-                        }, {
-                        'name': 'origin7',
-                        'one2one': targets[1].id,
-                        }])
-            for one2one, target in zip(one2ones, targets):
-                self.assert_(one2one)
-                self.assertEqual(one2one.one2one, target)
+        self.assertRaises(Exception, Timedelta.write, [timedelta1], {
+                'timedelta': 'test',
+                })
 
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Timedelta.create, [{
+                    'timedelta': 1,
+                    }])
 
-    def test0120one2many(self):
-        'Test One2Many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            for one2many, one2many_target in (
-                    (self.one2many, self.one2many_target),
-                    (self.one2many_reference, self.one2many_reference_target),
-                    ):
-                one2many1, = one2many.create([{
-                            'name': 'origin1',
-                            'targets': [
-                                ('create', [{
-                                            'name': 'target1',
-                                            }]),
-                                ],
-                            }])
-                self.assert_(one2many1)
-
-                self.assertEqual(len(one2many1.targets), 1)
-                target1, = one2many1.targets
-
-                # Try with target1 stored in cache
-                target1 = one2many_target(target1.id)
-                target1.origin
-                one2many1 = one2many(one2many1)
-                self.assertEqual(one2many1.targets, (target1,))
-
-                one2manys = one2many.search([
-                        ('targets', '=', 'target1'),
-                        ])
-                self.assertEqual(one2manys, [one2many1])
-
-                one2manys = one2many.search([
-                        ('targets', '!=', 'target1'),
-                        ])
-                self.assertEqual(one2manys, [])
-
-                one2manys = one2many.search([
-                        ('targets', 'in', [target1.id]),
-                        ])
-                self.assertEqual(one2manys, [one2many1])
-
-                one2manys = one2many.search([
-                        ('targets', 'in', [0]),
-                        ])
-                self.assertEqual(one2manys, [])
-
-                one2manys = one2many.search([
-                        ('targets', 'not in', (target1.id,)),
-                        ])
-                self.assertEqual(one2manys, [])
-
-                one2manys = one2many.search([
-                        ('targets', 'not in', [0]),
-                        ])
-                self.assertEqual(one2manys, [one2many1])
-
-                one2manys = one2many.search([
-                        ('targets.name', '=', 'target1'),
-                        ])
-                self.assertEqual(one2manys, [one2many1])
-
-                one2manys = one2many.search([
-                        ('targets.name', '!=', 'target1'),
-                        ])
-                self.assertEqual(one2manys, [])
-
-                one2many2, = one2many.create([{
-                            'name': 'origin2',
-                            }])
-                self.assert_(one2many2)
-
-                self.assertEqual(one2many2.targets, ())
-
-                one2manys = one2many.search([
-                        ('targets', '=', None),
-                        ])
-                self.assertEqual(one2manys, [one2many2])
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('write', [target1.id], {
-                                    'name': 'target1bis',
-                                    }),
-                            ],
-                        })
-                self.assertEqual(target1.name, 'target1bis')
+        self.assertRaises(Exception, Timedelta.write, [timedelta1], {
+                'timedelta': 1,
+                })
 
-                target2, = one2many_target.create([{
-                            'name': 'target2',
-                            }])
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('add', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(one2many1.targets,
-                    (target1, target2))
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('remove', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(one2many1.targets, (target1,))
-                target2, = one2many_target.search([
-                        ('id', '=', target2.id),
-                        ])
-                self.assert_(target2)
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('remove', [target1.id]),
-                            ],
-                        })
-                self.assertEqual(one2many1.targets, ())
-                targets = one2many_target.search([
-                        ('id', 'in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(targets, [target1, target2])
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('add', [target1.id, target2.id]),
-                            ],
-                        })
-                self.assertEqual(one2many1.targets,
-                    (target1, target2))
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('copy', [target1.id], {'name': 'copy1'}),
-                            ],
-                        })
-                targets = one2many_target.search([
-                        ('id', 'not in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(len(targets), 1)
-                self.assertEqual(targets[0].name, 'copy1')
-
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('copy', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(len(one2many1.targets), 4)
-                targets = one2many_target.search([
-                        ('id', 'not in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(len(targets), 2)
-                names = set([target.name for target in targets])
-                self.assertEqual(names, set(('copy1', 'target2')))
-
-                copy_ids = [target.id for target in targets]
-                one2many.write([one2many1], {
-                        'targets': [
-                            ('delete', [target2.id] + copy_ids),
-                            ],
-                        })
-                self.assertEqual(one2many1.targets, (target1,))
-                targets = one2many_target.search([
-                        ('id', '=', target2.id),
-                        ])
-                self.assertEqual(targets, [])
-
-                transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.one2many_required.create, [{
-                        'name': 'origin3',
-                        }])
-            transaction.cursor.rollback()
-
-            origin3_id, = self.one2many_required.create([{
-                        'name': 'origin3',
-                        'targets': [
-                            ('create', [{
-                                        'name': 'target3',
-                                        }]),
-                            ],
-                        }])
-            self.assert_(origin3_id)
-
-            self.one2many_size.create([{
-                        'targets': [('create', [{}])] * 3,
-                        }])
-            self.assertRaises(UserError, self.one2many_size.create, [{
-                        'targets': [('create', [{}])] * 4,
-                        }])
-            self.one2many_size_pyson.create([{
-                        'limit': 4,
-                        'targets': [('create', [{}])] * 4,
-                        }])
-            self.assertRaises(UserError, self.one2many_size_pyson.create, [{
-                        'limit': 2,
-                        'targets': [('create', [{}])] * 4,
-                        }])
-
-            transaction.cursor.rollback()
-
-    def test0130many2many(self):
-        'Test Many2Many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            for many2many, many2many_target in (
-                    (self.many2many, self.many2many_target),
-                    (self.many2many_reference,
-                        self.many2many_reference_target),
-                    ):
-                many2many1, = many2many.create([{
-                            'name': 'origin1',
-                            'targets': [
-                                ('create', [{
-                                            'name': 'target1',
-                                            }]),
-                                ],
-                            }])
-                self.assert_(many2many1)
-
-                self.assertEqual(len(many2many1.targets), 1)
-                target1, = many2many1.targets
-
-                many2manys = many2many.search([
-                        ('targets', '=', 'target1'),
-                        ])
-                self.assertEqual(many2manys, [many2many1])
-
-                many2manys = many2many.search([
-                        ('targets', '!=', 'target1'),
-                        ])
-                self.assertEqual(many2manys, [])
-
-                many2manys = many2many.search([
-                        ('targets', 'in', [target1.id]),
-                        ])
-                self.assertEqual(many2manys, [many2many1])
-
-                many2manys = many2many.search([
-                        ('targets', 'in', [0]),
-                        ])
-                self.assertEqual(many2manys, [])
-
-                many2manys = many2many.search([
-                        ('targets', 'not in', [target1.id]),
-                        ])
-                self.assertEqual(many2manys, [])
-
-                many2manys = many2many.search([
-                        ('targets', 'not in', [0]),
-                        ])
-                self.assertEqual(many2manys, [many2many1])
-
-                many2manys = many2many.search([
-                        ('targets.name', '=', 'target1'),
-                        ])
-                self.assertEqual(many2manys, [many2many1])
-
-                many2manys = many2many.search([
-                        ('targets.name', '!=', 'target1'),
-                        ])
-                self.assertEqual(many2manys, [])
-
-                many2many2, = many2many.create([{
-                            'name': 'origin2',
-                            }])
-                self.assert_(many2many2)
-
-                self.assertEqual(many2many2.targets, ())
-
-                many2manys = many2many.search([
-                        ('targets', '=', None),
-                        ])
-                self.assertEqual(many2manys, [many2many2])
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('write', [target1.id], {
-                                    'name': 'target1bis',
-                                    }),
-                            ],
-                        })
-                self.assertEqual(target1.name, 'target1bis')
-
-                target2, = many2many_target.create([{
-                            'name': 'target2',
-                            }])
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('add', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(many2many1.targets,
-                    (target1, target2))
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('remove', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(many2many1.targets, (target1,))
-                target2, = many2many_target.search([
-                        ('id', '=', target2.id),
-                        ])
-                self.assert_(target2)
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('remove', [target1.id]),
-                            ],
-                        })
-                self.assertEqual(many2many1.targets, ())
-                targets = many2many_target.search([
-                        ('id', 'in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(targets, [target1, target2])
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('add', [target1.id, target2.id]),
-                            ],
-                        })
-                self.assertEqual(many2many1.targets,
-                    (target1, target2))
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('copy', [target1.id], {'name': 'copy1'}),
-                            ],
-                        })
-                targets = many2many_target.search([
-                        ('id', 'not in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(len(targets), 1)
-                self.assertEqual(targets[0].name, 'copy1')
-
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('copy', [target2.id]),
-                            ],
-                        })
-                self.assertEqual(len(many2many1.targets), 4)
-                targets = many2many_target.search([
-                        ('id', 'not in', [target1.id, target2.id]),
-                        ])
-                self.assertEqual(len(targets), 2)
-                names = set([target.name for target in targets])
-                self.assertEqual(names, set(('copy1', 'target2')))
-
-                copy_ids = [target.id for target in targets]
-                many2many.write([many2many1], {
-                        'targets': [
-                            ('delete', [target2.id] + copy_ids),
-                            ],
-                        })
-                self.assertEqual(many2many1.targets, (target1,))
-                targets = many2many_target.search([
-                        ('id', '=', target2.id),
-                        ])
-                self.assertEqual(targets, [])
-
-                transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.many2many_required.create, [{
-                        'name': 'origin3',
-                        }])
-            transaction.cursor.rollback()
-
-            origin3_id, = self.many2many_required.create([{
-                        'name': 'origin3',
-                        'targets': [
-                            ('create', [{
-                                        'name': 'target3',
-                                        }]),
-                            ],
-                        }])
-            self.assert_(origin3_id)
-
-            self.many2many_size_target.create([{
-                        'name': str(i),
-                        } for i in range(6)])
-
-            transaction.cursor.rollback()
-
-    def test0140reference(self):
-        'Test Reference'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            target1, = self.reference_target.create([{
-                        'name': 'target1',
-                        }])
-            reference1, = self.reference.create([{
-                        'name': 'reference1',
-                        'reference': str(target1),
-                        }])
-            self.assert_(reference1)
-
-            self.assertEqual(reference1.reference, target1)
-
-            references = self.reference.search([
-                    ('reference', '=', str(target1)),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference', '=', (target1.__name__, target1.id)),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference', '=', [target1.__name__, target1.id]),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference.name', '=', 'target1',
-                        'test.reference.target'),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference', '!=', str(target1)),
-                    ])
-            self.assertEqual(references, [])
-
-            references = self.reference.search([
-                    ('reference', '!=', str(target1)),
-                    ])
-            self.assertEqual(references, [])
-
-            references = self.reference.search([
-                    ('reference', 'in', [str(target1)]),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference', 'in',
-                        [('test.reference.target', target1.id)]),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            references = self.reference.search([
-                    ('reference', 'in', [None]),
-                    ])
-            self.assertEqual(references, [])
-
-            references = self.reference.search([
-                    ('reference', 'not in', [str(target1)]),
-                    ])
-            self.assertEqual(references, [])
-
-            references = self.reference.search([
-                    ('reference', 'not in',
-                        [('test.reference.target', target1.id)]),
-                    ])
-            self.assertEqual(references, [])
-
-            references = self.reference.search([
-                    ('reference', 'not in', [None]),
-                    ])
-            self.assertEqual(references, [reference1])
-
-            reference2, = self.reference.create([{
-                        'name': 'reference2',
-                        }])
-            self.assert_(reference2)
-
-            self.assertEqual(reference2.reference, None)
-
-            references = self.reference.search([
-                    ('reference', '=', None),
-                    ])
-            self.assertEqual(references, [reference2])
-
-            target2, = self.reference_target.create([{
-                        'name': 'target2',
-                        }])
-
-            self.reference.write([reference2], {
-                    'reference': str(target2),
-                    })
-            self.assertEqual(reference2.reference, target2)
-
-            self.reference.write([reference2], {
-                    'reference': None,
-                    })
-            self.assertEqual(reference2.reference, None)
-
-            self.reference.write([reference2], {
-                    'reference': ('test.reference.target', target2.id),
-                    })
-            self.assertEqual(reference2.reference, target2)
-
-            reference3, = self.reference.create([{
-                        'name': 'reference3',
-                        'reference': ('test.reference.target', target1.id),
-                        }])
-            self.assert_(reference3)
-
-            self.assertRaises(UserError, self.reference_required.create, [{
-                        'name': 'reference4',
-                        }])
-            transaction.cursor.rollback()
-
-            target4, = self.reference_target.create([{
-                        'name': 'target4_id',
-                        }])
-
-            reference4, = self.reference_required.create([{
-                        'name': 'reference4',
-                        'reference': str(target4),
-                        }])
-            self.assert_(reference4)
-
-            transaction.cursor.rollback()
-
-    def test0150property(self):
-        'Test Property with supported field types'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-
-            # Test Char
-            prop_a, = self.property_.create([{'char': 'Test'}])
-            self.assert_(prop_a)
-            self.assertEqual(prop_a.char, 'Test')
-
-            prop_b, = self.property_.create([{}])
-            self.assert_(prop_b)
-            self.assertEqual(prop_b.char, None)
-
-            prop_c, = self.property_.create([{'char': 'FooBar'}])
-            self.assert_(prop_c)
-            self.assertEqual(prop_c.char, 'FooBar')
-
-            props = self.property_.search([('char', '=', 'Test')])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([('char', '=', None)])
-            self.assertEqual(props, [prop_b])
-
-            props = self.property_.search([('char', '!=', None)])
-            self.assertEqual(props, [prop_a, prop_c])
-
-            props = self.property_.search([('char', 'like', 'Tes%')])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([('char', 'like', '%Bar')])
-            self.assertEqual(props, [prop_c])
-
-            props = self.property_.search([('char', 'not like', 'Tes%')])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            props = self.property_.search([('char', 'ilike', 'tes%')])
-            self.assert_(props, [prop_a])
-
-            props = self.property_.search([('char', 'ilike', '%bar')])
-            self.assertEqual(props, [prop_c])
-
-            props = self.property_.search([('char', 'not ilike', 'tes%')])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            props = self.property_.search([('char', 'in', ['Test'])])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([
-                    ('char', 'in', ['Test', 'FooBar'])])
-            self.assertEqual(props, [prop_a, prop_c])
-
-            props = self.property_.search([
-                    ('char', 'not in', ['Test', 'FooBar'])])
-            self.assertEqual(props, [prop_b])
-
-            # Test default value
-            property_field, = self.model_field.search([
-                    ('model.model', '=', 'test.property'),
-                    ('name', '=', 'char'),
-                    ], limit=1)
-            self.ir_property.create([{
-                        'field': property_field.id,
-                        'value': ',DEFAULT_VALUE',
-                        }])
-
-            prop_d, = self.property_.create([{}])
-            self.assert_(prop_d)
-            self.assertEqual(prop_d.char, 'DEFAULT_VALUE')
-
-            props = self.property_.search([('char', '!=', None)])
-            self.assertEqual(props, [prop_a, prop_c, prop_d])
-
-            self.property_.write([prop_a], {'char': None})
-            self.assertEqual(prop_a.char, None)
-
-            self.property_.write([prop_b], {'char': 'Test'})
-            self.assertEqual(prop_b.char, 'Test')
-
-            transaction.cursor.rollback()
-
-            # Test Many2One
-            char_a, = self.char.create([{'char': 'Test'}])
-            self.assert_(char_a)
-
-            char_b, = self.char.create([{'char': 'FooBar'}])
-            self.assert_(char_b)
-
-            prop_a, = self.property_.create([{'many2one': char_a.id}])
-            self.assert_(prop_a)
-            self.assertEqual(prop_a.many2one, char_a)
-
-            prop_b, = self.property_.create([{'many2one': char_b.id}])
-            self.assert_(prop_b)
-            self.assertEqual(prop_b.many2one, char_b)
-
-            prop_c, = self.property_.create([{}])
-            self.assert_(prop_c)
-            self.assertEqual(prop_c.many2one, None)
-
-            props = self.property_.search([('many2one', '=', char_a.id)])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([('many2one', '!=', None)])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([('many2one', '=', None)])
-            self.assertEqual(props, [prop_c])
-
-            self.assertEqual(prop_a.many2one, char_a)
-
-            props = self.property_.search([
-                    ('many2one', 'in', [char_a.id, char_b.id])])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([
-                    ('many2one', 'not in', [char_a.id, char_b.id])])
-            self.assertEqual(props, [prop_c])
-
-            self.property_.write([prop_b], {'many2one': char_a.id})
-            self.assertEqual(prop_b.many2one, char_a)
-
-            transaction.cursor.rollback()
-
-            # Test Numeric
-            prop_a, = self.property_.create([{'numeric': Decimal('1.1')}])
-            self.assert_(prop_a)
-            self.assertEqual(prop_a.numeric, Decimal('1.1'))
-
-            prop_b, = self.property_.create([{'numeric': Decimal('2.6')}])
-            self.assert_(prop_b)
-            self.assertEqual(prop_b.numeric, Decimal('2.6'))
-
-            prop_c, = self.property_.create([{}])
-            self.assert_(prop_c)
-            self.assertEqual(prop_c.numeric, None)
-
-            props = self.property_.search([('numeric', '!=', None)])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([('numeric', '=', None)])
-            self.assertEqual(props, [prop_c])
-
-            props = self.property_.search([
-                    ('numeric', '=', Decimal('1.1')),
-                    ])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([
-                    ('numeric', '!=', Decimal('1.1'))])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            props = self.property_.search([
-                    ('numeric', '<', Decimal('2.6')),
-                    ])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([
-                    ('numeric', '<=', Decimal('2.6'))])
-            self.assertEqual(props, [prop_a, prop_b])
+        self.assertRaises(UserError, TimedeltaRequired.create, [{}])
+        transaction.rollback()
 
-            props = self.property_.search([
-                    ('numeric', '>', Decimal('1.1')),
-                    ])
-            self.assertEqual(props, [prop_b])
-
-            props = self.property_.search([
-                    ('numeric', '>=', Decimal('1.1'))])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([
-                    ('numeric', 'in', [Decimal('1.1')])])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([
-                    ('numeric', 'in', [Decimal('1.1'), Decimal('2.6')])])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([
-                    ('numeric', 'not in', [Decimal('1.1')])])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            props = self.property_.search([
-                    ('numeric', 'not in', [Decimal('1.1'), Decimal('2.6')])])
-            self.assertEqual(props, [prop_c])
-
-            # Test default value
-            property_field, = self.model_field.search([
-                    ('model.model', '=', 'test.property'),
-                    ('name', '=', 'numeric'),
-                    ], limit=1)
-            self.ir_property.create([{
-                        'field': property_field.id,
-                        'value': ',3.7',
-                        }])
-
-            prop_d, = self.property_.create([{}])
-            self.assert_(prop_d)
-            self.assertEqual(prop_d.numeric, Decimal('3.7'))
-
-            self.property_.write([prop_a], {'numeric': None})
-            self.assertEqual(prop_a.numeric, None)
-
-            self.property_.write([prop_b], {'numeric': Decimal('3.11')})
-            self.assertEqual(prop_b.numeric, Decimal('3.11'))
-
-            transaction.cursor.rollback()
-
-            # Test Selection
-            prop_a, = self.property_.create([{'selection': 'option_a'}])
-            self.assert_(prop_a)
-            self.assertEqual(prop_a.selection, 'option_a')
-
-            prop_b, = self.property_.create([{'selection': 'option_b'}])
-            self.assert_(prop_b)
-            self.assertEqual(prop_b.selection, 'option_b')
-
-            prop_c, = self.property_.create([{}])
-            self.assert_(prop_c)
-            self.assertEqual(prop_c.selection, None)
-
-            props = self.property_.search([('selection', '=', 'option_a')])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([('selection', '!=', None)])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([('selection', '=', None)])
-            self.assertEqual(props, [prop_c])
-
-            props = self.property_.search([('selection', '!=', 'option_a')])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            props = self.property_.search([
-                    ('selection', 'in', ['option_a'])])
-            self.assertEqual(props, [prop_a])
-
-            props = self.property_.search([
-                    ('selection', 'in', ['option_a', 'option_b'])])
-            self.assertEqual(props, [prop_a, prop_b])
-
-            props = self.property_.search([
-                    ('selection', 'not in', ['option_a'])])
-            self.assertEqual(props, [prop_b, prop_c])
-
-            # Test default value
-            property_field, = self.model_field.search([
-                    ('model.model', '=', 'test.property'),
-                    ('name', '=', 'selection'),
-                    ], limit=1)
-            self.ir_property.create([{
-                        'field': property_field.id,
-                        'value': ',option_a',
-                        }])
-
-            prop_d, = self.property_.create([{}])
-            self.assert_(prop_d)
-            self.assertEqual(prop_d.selection, 'option_a')
-
-            self.property_.write([prop_a], {'selection': None})
-            self.assertEqual(prop_a.selection, None)
-
-            self.property_.write([prop_c], {'selection': 'option_b'})
-            self.assertEqual(prop_c.selection, 'option_b')
-
-            transaction.cursor.rollback()
-
-    def test0160selection(self):
-        'Test Selection'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            selection1, = self.selection.create([{'select': 'arabic'}])
-            self.assert_(selection1)
-            self.assertEqual(selection1.select, 'arabic')
-            self.assertEqual(selection1.select_string, 'Arabic')
-
-            selection2, = self.selection.create([{'select': None}])
-            self.assert_(selection2)
-            self.assertEqual(selection2.select, None)
-            self.assertEqual(selection2.select_string, '')
-
-            self.assertRaises(UserError, self.selection.create,
-                [{'select': 'chinese'}])
-
-            selection3, = self.selection.create(
-                [{'select': 'arabic', 'dyn_select': '1'}])
-            self.assert_(selection3)
-            self.assertEqual(selection3.select, 'arabic')
-            self.assertEqual(selection3.dyn_select, '1')
-
-            selection4, = self.selection.create(
-                [{'select': 'hexa', 'dyn_select': '0x3'}])
-            self.assert_(selection4)
-            self.assertEqual(selection4.select, 'hexa')
-            self.assertEqual(selection4.dyn_select, '0x3')
-
-            selection5, = self.selection.create(
-                [{'select': 'hexa', 'dyn_select': None}])
-            self.assert_(selection5)
-            self.assertEqual(selection5.select, 'hexa')
-            self.assertEqual(selection5.dyn_select, None)
-
-            self.assertRaises(UserError, self.selection.create,
-                [{'select': 'arabic', 'dyn_select': '0x3'}])
-            self.assertRaises(UserError, self.selection.create,
-                [{'select': 'hexa', 'dyn_select': '3'}])
-
-            self.assertRaises(UserError, self.selection_required.create, [{}])
-            transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.selection_required.create,
-                [{'select': None}])
-            transaction.cursor.rollback()
-
-            selection6, = self.selection_required.create([{'select': 'latin'}])
-            self.assert_(selection6)
-            self.assertEqual(selection6.select, 'latin')
-
-    def test0170dict(self):
-        'Test Dict'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-
-            self.dict_schema.create([{
-                        'name': 'a',
-                        'string': 'A',
-                        'type_': 'integer',
-                        }, {
-                        'name': 'b',
-                        'string': 'B',
-                        'type_': 'integer',
-                        }, {
-                        'name': 'type',
-                        'string': 'Type',
-                        'type_': 'selection',
-                        'selection': ('arabic: Arabic\n'
-                            'hexa: Hexadecimal'),
-                        }])
-
-            dict1, = self.dict_.create([{
-                        'dico': {'a': 1, 'b': 2},
-                        }])
-            self.assert_(dict1.dico == {'a': 1, 'b': 2})
-
-            self.dict_.write([dict1], {'dico': {'z': 26}})
-            self.assert_(dict1.dico == {'z': 26})
-
-            dict1.dico = {
-                'a': 1,
-                'type': 'arabic',
-                }
-            dict1.save()
-            self.assertEqual(dict1.dico, {'a': 1, 'type': 'arabic'})
-            self.assertEqual(dict1.dico_string, {
-                    'a': 1,
-                    'type': 'Arabic',
-                    })
-            self.assertEqual(dict1.dico_string_keys, {
-                    'a': 'A',
-                    'type': 'Type',
-                    })
-
-            dict2, = self.dict_.create([{}])
-            self.assert_(dict2.dico is None)
-
-            dict3, = self.dict_default.create([{}])
-            self.assert_(dict3.dico == {'a': 1})
-
-            self.assertRaises(UserError, self.dict_required.create, [{}])
-            transaction.cursor.rollback()
-
-            dict4, = self.dict_required.create([{'dico': dict(a=1)}])
-            self.assert_(dict4.dico == {'a': 1})
-
-            self.assertRaises(UserError, self.dict_required.create,
-                [{'dico': {}}])
-            transaction.cursor.rollback()
-
-    def test0180binary(self):
-        'Test Binary'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            bin1, = self.binary.create([{
-                        'binary': fields.Binary.cast(b'foo'),
-                        }])
-            self.assert_(bin1.binary == fields.Binary.cast(b'foo'))
-
-            self.binary.write([bin1], {'binary': fields.Binary.cast(b'bar')})
-            self.assert_(bin1.binary == fields.Binary.cast(b'bar'))
-
-            with transaction.set_context({'test.binary.binary': 'size'}):
-                bin1_size = self.binary(bin1.id)
-                self.assert_(bin1_size.binary == len(b'bar'))
-                self.assert_(bin1_size.binary != fields.Binary.cast(b'bar'))
-
-            bin2, = self.binary.create([{}])
-            self.assert_(bin2.binary is None)
-
-            bin3, = self.binary_default.create([{}])
-            self.assert_(bin3.binary == fields.Binary.cast(b'default'))
-
-            self.assertRaises(UserError, self.binary_required.create, [{}])
-            transaction.cursor.rollback()
-
-            bin4, = self.binary_required.create([{
-                        'binary': fields.Binary.cast(b'baz'),
-                        }])
-            self.assert_(bin4.binary == fields.Binary.cast(b'baz'))
-
-            self.assertRaises(UserError, self.binary_required.create,
-                [{'binary': fields.Binary.cast(b'')}])
-
-            transaction.cursor.rollback()
-
-    def test0190many2one(self):
-        'Test Many2One'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-
-            # Not respecting the domain raise an Error
-            m2o_1, = self.m2o_target.create([{'value': 1}])
-            self.assertRaises(UserError, self.m2o_domain_validation.create,
-                [{'many2one': m2o_1}])
-
-            # Respecting the domain works
-            m2o_6, = self.m2o_target.create([{'value': 6}])
-            domain, = self.m2o_domain_validation.create([{'many2one': m2o_6}])
-            self.assert_(domain)
-            self.assertEqual(domain.many2one.value, 6)
-
-            # Inactive records are taken into account
-            m2o_6.active = False
-            m2o_6.save()
-            domain.dummy = 'Dummy'
-            domain.save()
-
-            # Testing order_by
-            for value in (5, 3, 2):
-                m2o, = self.m2o_target.create([{'value': value}])
-                self.m2o_orderby.create([{'many2one': m2o}])
-
-            search = self.m2o_orderby.search([], order=[('many2one', 'ASC')])
-            self.assertTrue(all(x.many2one.value <= y.many2one.value
-                    for x, y in zip(search, search[1:])))
-
-            search = self.m2o_orderby.search([],
-                order=[('many2one.id', 'ASC')])
-            self.assertTrue(all(x.many2one.id <= y.many2one.id
-                    for x, y in zip(search, search[1:])))
-
-            search = self.m2o_orderby.search([],
-                order=[('many2one.value', 'ASC')])
-            self.assertTrue(all(x.many2one.value <= y.many2one.value
-                    for x, y in zip(search, search[1:])))
-
-            transaction.cursor.rollback()
-
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-
-            target1, target2 = self.m2o_target.create([
-                    {'value': 1},
-                    {'value': 2},
-                    ])
-
-            search1, search2 = self.m2o_search.create([
-                    {'many2one': target1.id},
-                    {'many2one': target2.id},
-                    ])
-
-            # Search join
-            self.m2o_search.target_search = 'join'
-            self.assertEqual(self.m2o_search.search([
-                        ('many2one.value', '=', 1),
-                        ]), [search1])
-
-            # Search subquery
-            self.m2o_search.target_search = 'subquery'
-            self.assertEqual(self.m2o_search.search([
-                        ('many2one.value', '=', 1),
-                        ]), [search1])
-
-    def test0200timedelta(self):
-        'Test timedelta'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-
-            minute = datetime.timedelta(minutes=1)
-            hour = datetime.timedelta(hours=1)
-            day = datetime.timedelta(days=1)
-            default_timedelta = datetime.timedelta(seconds=3600)
-
-            timedelta1, = self.timedelta.create([{
-                        'timedelta': hour,
-                        }])
-            self.assert_(timedelta1)
-            self.assertEqual(timedelta1.timedelta, hour)
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '=', hour),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '=', day),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '=', None),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '!=', day),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '!=', None),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', [hour]),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', [day]),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', [minute]),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', [None]),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', []),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'not in', [hour]),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'not in', [day]),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'not in', [None]),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'not in', []),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<', day),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<', minute),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<', hour),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<=', hour),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<=', minute),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '<=', day),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>', day),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>', minute),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>', hour),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>=', day),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>=', minute),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '>=', hour),
-                    ])
-            self.assertEqual(timedelta, [timedelta1])
-
-            timedelta2, = self.timedelta.create([{
-                        'timedelta': minute,
-                        }])
-            self.assert_(timedelta2)
-            self.assertEqual(timedelta2.timedelta, minute)
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', '=', minute),
-                    ])
-            self.assertEqual(timedelta, [timedelta2])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'in', [minute, hour]),
-                    ])
-            self.assertEqual(timedelta, [timedelta1, timedelta2])
-
-            timedelta = self.timedelta.search([
-                    ('timedelta', 'not in', [minute, hour]),
-                    ])
-            self.assertEqual(timedelta, [])
-
-            timedelta3, = self.timedelta.create([{}])
-            self.assert_(timedelta3)
-            self.assertEqual(timedelta3.timedelta, None)
-
-            timedelta4, = self.timedelta_default.create([{}])
-            self.assert_(timedelta4)
-            self.assertEqual(timedelta4.timedelta, default_timedelta)
-
-            self.timedelta.write([timedelta1], {
-                    'timedelta': minute,
-                    })
-            self.assertEqual(timedelta1.timedelta, minute)
-
-            self.timedelta.write([timedelta2], {
+        timedelta6, = TimedeltaRequired.create([{
                     'timedelta': day,
-                    })
-            self.assertEqual(timedelta2.timedelta, day)
-
-            self.assertRaises(Exception, self.timedelta.create, [{
-                        'timedelta': 'test',
-                        }])
-
-            self.assertRaises(Exception, self.timedelta.write, [timedelta1], {
-                    'timedelta': 'test',
-                    })
-
-            self.assertRaises(Exception, self.timedelta.create, [{
-                        'timedelta': 1,
-                        }])
-
-            self.assertRaises(Exception, self.timedelta.write, [timedelta1], {
-                    'timedelta': 1,
-                    })
-
-            self.assertRaises(UserError, self.timedelta_required.create, [{}])
-            transaction.cursor.rollback()
-
-            timedelta6, = self.timedelta_required.create([{
-                        'timedelta': day,
-                        }])
-            self.assert_(timedelta6)
-
-            timedelta7, = self.timedelta.create([{
-                        'timedelta': None,
-                        }])
-            self.assert_(timedelta7)
+                    }])
+        self.assert_(timedelta6)
 
-            transaction.cursor.rollback()
+        timedelta7, = Timedelta.create([{
+                    'timedelta': None,
+                    }])
+        self.assert_(timedelta7)
 
 
 def suite():
diff --git a/trytond/tests/test_history.py b/trytond/tests/test_history.py
index 0131dac..a8cd77b 100644
--- a/trytond/tests/test_history.py
+++ b/trytond/tests/test_history.py
@@ -3,9 +3,9 @@
 import unittest
 import datetime
 
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.exceptions import UserError
 from trytond import backend
 
@@ -13,286 +13,267 @@ from trytond import backend
 class HistoryTestCase(unittest.TestCase):
     'Test History'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
+    @with_transaction()
     def tearDown(self):
-        History = POOL.get('test.history')
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            cursor = transaction.cursor
-            table = History.__table__()
-            history_table = History.__table_history__()
-            cursor.execute(*table.delete())
-            cursor.execute(*history_table.delete())
-            cursor.commit()
-
-    def test0010read(self):
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
+        cursor = transaction.connection.cursor()
+        table = History.__table__()
+        history_table = History.__table_history__()
+        cursor.execute(*table.delete())
+        cursor.execute(*history_table.delete())
+        transaction.commit()
+
+    @with_transaction()
+    def test_read(self):
         'Test read history'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
         # Create some history entry
         # It is needed to commit to have different timestamps
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        first = history.create_date
+
+        transaction.commit()
+
+        history = History(history_id)
+        history.value = 2
+        history.save()
+        second = history.write_date
+
+        transaction.commit()
+
+        history = History(history_id)
+        history.value = 3
+        history.save()
+        third = history.write_date
+
+        transaction.commit()
+
+        for timestamp, value in [
+                (first, 1),
+                (second, 2),
+                (third, 3),
+                (datetime.datetime.now(), 3),
+                (datetime.datetime.max, 3),
+                ]:
+            with Transaction().set_context(_datetime=timestamp):
+                history = History(history_id)
+                self.assertEqual(history.value, value)
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            first = history.create_date
-
-            transaction.cursor.commit()
-
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 2
-            history.save()
-            second = history.write_date
-
-            transaction.cursor.commit()
-
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 3
-            history.save()
-            third = history.write_date
-
-            transaction.cursor.commit()
-
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for timestamp, value in [
-                    (first, 1),
-                    (second, 2),
-                    (third, 3),
-                    (datetime.datetime.now(), 3),
-                    (datetime.datetime.max, 3),
-                    ]:
-                with Transaction().set_context(_datetime=timestamp):
-                    history = History(history_id)
-                    self.assertEqual(history.value, value)
-
-            with Transaction().set_context(_datetime=datetime.datetime.min):
-                self.assertRaises(UserError, History.read, [history_id])
+        with Transaction().set_context(_datetime=datetime.datetime.min):
+            self.assertRaises(UserError, History.read, [history_id])
 
     @unittest.skipUnless(backend.name() == 'postgresql',
         'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
-    def test0020read_same_timestamp(self):
+    @with_transaction()
+    def test_read_same_timestamp(self):
         'Test read history with same timestamp'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            first = history.create_date
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        first = history.create_date
 
-            history.value = 2
-            history.save()
-            second = history.write_date
+        history.value = 2
+        history.save()
+        second = history.write_date
 
-            self.assertEqual(first, second)
+        self.assertEqual(first, second)
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 3
-            history.save()
-            third = history.write_date
+        history = History(history_id)
+        history.value = 3
+        history.save()
+        third = history.write_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for timestamp, value in [
-                    (first, 2),
-                    (third, 3),
-                    ]:
-                with Transaction().set_context(_datetime=timestamp):
-                    history = History(history_id)
-                    self.assertEqual(history.value, value)
+        for timestamp, value in [
+                (first, 2),
+                (third, 3),
+                ]:
+            with Transaction().set_context(_datetime=timestamp):
+                history = History(history_id)
+                self.assertEqual(history.value, value)
 
-    def test0030history_revisions(self):
+    @with_transaction()
+    def test_history_revisions(self):
         'Test history revisions'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            first = history.create_date
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        first = history.create_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 2
-            history.save()
-            second = history.write_date
+        history = History(history_id)
+        history.value = 2
+        history.save()
+        second = history.write_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 3
-            history.save()
-            third = history.write_date
+        history = History(history_id)
+        history.value = 3
+        history.save()
+        third = history.write_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            revisions = History.history_revisions([history_id])
-            self.assertEqual(revisions, [
-                    (third, history_id, u'Administrator'),
-                    (second, history_id, u'Administrator'),
-                    (first, history_id, u'Administrator'),
-                    ])
+        revisions = History.history_revisions([history_id])
+        self.assertEqual(revisions, [
+                (third, history_id, u'Administrator'),
+                (second, history_id, u'Administrator'),
+                (first, history_id, u'Administrator'),
+                ])
 
-    def test0040restore_history(self):
+    @with_transaction()
+    def test_restore_history(self):
         'Test restore history'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            first = history.create_date
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        first = history.create_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 2
-            history.save()
+        history = History(history_id)
+        history.value = 2
+        history.save()
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.restore_history([history_id], first)
-            history = History(history_id)
-            self.assertEqual(history.value, 1)
+        History.restore_history([history_id], first)
+        history = History(history_id)
+        self.assertEqual(history.value, 1)
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.restore_history([history_id], datetime.datetime.min)
-            self.assertRaises(UserError, History.read, [history_id])
+        transaction.rollback()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.delete([History(history_id)])
+        History.restore_history([history_id], datetime.datetime.min)
+        self.assertRaises(UserError, History.read, [history_id])
 
-            transaction.cursor.commit()
+        transaction.rollback()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.restore_history([history_id], datetime.datetime.max)
-            self.assertRaises(UserError, History.read, [history_id])
+        History.delete([History(history_id)])
+
+        transaction.commit()
+
+        History.restore_history([history_id], datetime.datetime.max)
+        self.assertRaises(UserError, History.read, [history_id])
 
-    def test0041restore_history_before(self):
+    @with_transaction()
+    def test_restore_history_before(self):
         'Test restore history before'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
+        history = History(value=1)
+        history.save()
+        history_id = history.id
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 2
-            history.save()
-            second = history.write_date
+        history = History(history_id)
+        history.value = 2
+        history.save()
+        second = history.write_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 3
-            history.save()
+        history = History(history_id)
+        history.value = 3
+        history.save()
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.restore_history_before([history_id], second)
-            history = History(history_id)
-            self.assertEqual(history.value, 1)
+        History.restore_history_before([history_id], second)
+        history = History(history_id)
+        self.assertEqual(history.value, 1)
 
     @unittest.skipUnless(backend.name() == 'postgresql',
         'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
-    def test0045restore_history_same_timestamp(self):
+    @with_transaction()
+    def test_restore_history_same_timestamp(self):
         'Test restore history with same timestamp'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            first = history.create_date
-            history.value = 2
-            history.save()
-            second = history.create_date
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        first = history.create_date
+        history.value = 2
+        history.save()
+        second = history.create_date
 
-            self.assertEqual(first, second)
+        self.assertEqual(first, second)
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 3
-            history.save()
+        history = History(history_id)
+        history.value = 3
+        history.save()
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            History.restore_history([history_id], first)
-            history = History(history_id)
-            self.assertEqual(history.value, 2)
+        History.restore_history([history_id], first)
+        history = History(history_id)
+        self.assertEqual(history.value, 2)
 
-    def test0050ordered_search(self):
+    @with_transaction()
+    def test_ordered_search(self):
         'Test ordered search of history models'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
         order = [('value', 'ASC')]
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            first_id = history.id
-            first_stamp = history.create_date
-            transaction.cursor.commit()
+        history = History(value=1)
+        history.save()
+        first_id = history.id
+        first_stamp = history.create_date
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=2)
-            history.save()
-            second_id = history.id
-            second_stamp = history.create_date
+        history = History(value=2)
+        history.save()
+        second_id = history.id
+        second_stamp = history.create_date
 
-            transaction.cursor.commit()
+        transaction.commit()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            first, second = History.search([], order=order)
+        first, second = History.search([], order=order)
 
-            self.assertEqual(first.id, first_id)
-            self.assertEqual(second.id, second_id)
+        self.assertEqual(first.id, first_id)
+        self.assertEqual(second.id, second_id)
 
-            first.value = 3
-            first.save()
-            third_stamp = first.write_date
-            transaction.cursor.commit()
+        first.value = 3
+        first.save()
+        third_stamp = first.write_date
+        transaction.commit()
 
         results = [
             (first_stamp, [first]),
@@ -301,20 +282,18 @@ class HistoryTestCase(unittest.TestCase):
             (datetime.datetime.now(), [second, first]),
             (datetime.datetime.max, [second, first]),
             ]
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for timestamp, instances in results:
-                with Transaction().set_context(_datetime=timestamp):
-                    records = History.search([], order=order)
-                    self.assertEqual(records, instances)
+        for timestamp, instances in results:
+            with Transaction().set_context(_datetime=timestamp):
+                records = History.search([], order=order)
+                self.assertEqual(records, instances)
+            transaction.rollback()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            to_delete, _ = History.search([], order=order)
+        to_delete, _ = History.search([], order=order)
 
-            self.assertEqual(to_delete.id, second.id)
+        self.assertEqual(to_delete.id, second.id)
 
-            History.delete([to_delete])
-            transaction.cursor.commit()
+        History.delete([to_delete])
+        transaction.commit()
 
         results = [
             (first_stamp, [first]),
@@ -323,31 +302,32 @@ class HistoryTestCase(unittest.TestCase):
             (datetime.datetime.now(), [first]),
             (datetime.datetime.max, [first]),
             ]
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for timestamp, instances in results:
-                with Transaction().set_context(_datetime=timestamp,
-                        from_test=True):
-                    records = History.search([], order=order)
-                    self.assertEqual(records, instances)
+        for timestamp, instances in results:
+            with Transaction().set_context(_datetime=timestamp,
+                    from_test=True):
+                records = History.search([], order=order)
+                self.assertEqual(records, instances)
+            transaction.rollback()
 
     @unittest.skipUnless(backend.name() == 'postgresql',
         'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
-    def test0060_ordered_search_same_timestamp(self):
+    @with_transaction()
+    def test_ordered_search_same_timestamp(self):
         'Test ordered search  with same timestamp'
-        History = POOL.get('test.history')
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
         order = [('value', 'ASC')]
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            first_stamp = history.create_date
-            history.value = 4
-            history.save()
-            second_stamp = history.write_date
+        history = History(value=1)
+        history.save()
+        first_stamp = history.create_date
+        history.value = 4
+        history.save()
+        second_stamp = history.write_date
 
-            self.assertEqual(first_stamp, second_stamp)
-            transaction.cursor.commit()
+        self.assertEqual(first_stamp, second_stamp)
+        transaction.commit()
 
         results = [
             (second_stamp, [history], [4]),
@@ -355,123 +335,129 @@ class HistoryTestCase(unittest.TestCase):
             (datetime.datetime.max, [history], [4]),
             ]
 
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for timestamp, instances, values in results:
-                with Transaction().set_context(_datetime=timestamp,
-                        last_test=True):
-                    records = History.search([], order=order)
-                    self.assertEqual(records, instances)
-                    self.assertEqual([x.value for x in records], values)
+        for timestamp, instances, values in results:
+            with Transaction().set_context(_datetime=timestamp,
+                    last_test=True):
+                records = History.search([], order=order)
+                self.assertEqual(records, instances)
+                self.assertEqual([x.value for x in records], values)
+            transaction.rollback()
 
-    def test0070_browse(self):
+    @with_transaction()
+    def test_browse(self):
         'Test browsing history'
-        History = POOL.get('test.history')
-        Line = POOL.get('test.history.line')
-
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(value=1)
-            history.save()
-            history_id = history.id
-            line_a = Line(name='a', history=history)
-            line_a.save()
-            line_a_id = line_a.id
-            line_b = Line(name='b', history=history)
-            line_b.save()
-            line_b_id = line_b.id
-
-            first_stamp = line_b.create_date
+        pool = Pool()
+        History = pool.get('test.history')
+        Line = pool.get('test.history.line')
+        transaction = Transaction()
 
-            transaction.cursor.commit()
+        history = History(value=1)
+        history.save()
+        history_id = history.id
+        line_a = Line(name='a', history=history)
+        line_a.save()
+        line_a_id = line_a.id
+        line_b = Line(name='b', history=history)
+        line_b.save()
+        line_b_id = line_b.id
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            history.value = 2
-            history.save()
+        first_stamp = line_b.create_date
 
-            Line.delete([Line(line_b_id)])
+        history.stamp = first_stamp
+        history.save()
 
-            line_a = Line(line_a_id)
-            line_a.name = 'c'
-            line_a.save()
+        transaction.commit()
 
-            second_stamp = line_a.write_date
+        history = History(history_id)
+        history.value = 2
+        history.save()
 
-            transaction.cursor.commit()
+        Line.delete([Line(line_b_id)])
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            history = History(history_id)
-            self.assertEqual(history.value, 2)
-            self.assertEqual([l.name for l in history.lines], ['c'])
+        line_a = Line(line_a_id)
+        line_a.name = 'c'
+        line_a.save()
 
-            with Transaction().set_context(_datetime=first_stamp):
-                history = History(history_id)
-            self.assertEqual(history.value, 1)
-            self.assertEqual([l.name for l in history.lines], ['a', 'b'])
+        second_stamp = line_a.write_date
 
-            with Transaction().set_context(_datetime=second_stamp):
-                history = History(history_id)
-            self.assertEqual(history.value, 2)
-            self.assertEqual([l.name for l in history.lines], ['c'])
+        transaction.commit()
 
-    def test0080_search_cursor_max(self):
-        'Test search with number of history entries at cursor.IN_MAX'
-        History = POOL.get('test.history')
+        history = History(history_id)
+        self.assertEqual(history.value, 2)
+        self.assertEqual([l.name for l in history.lines], ['c'])
+        self.assertEqual(history.stamp, first_stamp)
+        self.assertEqual(
+            [l.name for l in history.lines_at_stamp], ['a', 'b'])
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            cursor = transaction.cursor
+        with Transaction().set_context(_datetime=first_stamp):
+            history = History(history_id)
+        self.assertEqual(history.value, 1)
+        self.assertEqual([l.name for l in history.lines], ['a', 'b'])
 
-            history = History(value=-1)
+        with Transaction().set_context(_datetime=second_stamp):
+            history = History(history_id)
+        self.assertEqual(history.value, 2)
+        self.assertEqual([l.name for l in history.lines], ['c'])
+        self.assertEqual(history.stamp, first_stamp)
+        self.assertEqual(
+            [l.name for l in history.lines_at_stamp], ['a', 'b'])
+
+    @with_transaction()
+    def test_search_cursor_max(self):
+        'Test search with number of history entries at database.IN_MAX'
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
+        database = transaction.database
+
+        history = History(value=-1)
+        history.save()
+
+        for history.value in range(database.IN_MAX + 1):
             history.save()
 
-            for history.value in range(cursor.IN_MAX + 1):
-                history.save()
-
-            with transaction.set_context(_datetime=datetime.datetime.max):
-                record, = History.search([])
+        with transaction.set_context(_datetime=datetime.datetime.max):
+            record, = History.search([])
 
-                self.assertEqual(record.value, cursor.IN_MAX)
+            self.assertEqual(record.value, database.IN_MAX)
 
-    def test0090_search_cursor_max_entries(self):
-        'Test search for skipping first history entries at cursor.IN_MAX'
-        History = POOL.get('test.history')
+    @with_transaction()
+    def test_search_cursor_max_entries(self):
+        'Test search for skipping first history entries at database.IN_MAX'
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
+        database = transaction.database
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            cursor = transaction.cursor
+        for i in xrange(0, 2):
+            history = History(value=-1)
+            history.save()
 
-            for i in xrange(0, 2):
-                history = History(value=-1)
+            for history.value in range(database.IN_MAX + 1):
                 history.save()
 
-                for history.value in range(cursor.IN_MAX + 1):
-                    history.save()
-
-            with transaction.set_context(_datetime=datetime.datetime.max):
-                records = History.search([])
-
-                self.assertEqual({r.value for r in records}, {cursor.IN_MAX})
-                self.assertEqual(len(records), 2)
+        with transaction.set_context(_datetime=datetime.datetime.max):
+            records = History.search([])
 
-    def test0100_search_cursor_max_histories(self):
-        'Test search with number of histories at cursor.IN_MAX'
-        History = POOL.get('test.history')
+            self.assertEqual({r.value for r in records}, {database.IN_MAX})
+            self.assertEqual(len(records), 2)
 
-        with Transaction().start(DB_NAME, USER,
-                                 context=CONTEXT) as transaction:
-            cursor = transaction.cursor
+    @with_transaction()
+    def test_search_cursor_max_histories(self):
+        'Test search with number of histories at database.IN_MAX'
+        pool = Pool()
+        History = pool.get('test.history')
+        transaction = Transaction()
+        database = transaction.database
 
-            n = cursor.IN_MAX + 1
-            History.create([{'value': 1}] * n)
+        n = database.IN_MAX + 1
+        History.create([{'value': 1}] * n)
 
-            with transaction.set_context(_datetime=datetime.datetime.max):
-                records = History.search([])
+        with transaction.set_context(_datetime=datetime.datetime.max):
+            records = History.search([])
 
-                self.assertEqual({r.value for r in records}, {1})
-                self.assertEqual(len(records), n)
+            self.assertEqual({r.value for r in records}, {1})
+            self.assertEqual(len(records), n)
 
 
 def suite():
diff --git a/trytond/tests/test_importdata.py b/trytond/tests/test_importdata.py
index 594b34f..748ffcc 100644
--- a/trytond/tests/test_importdata.py
+++ b/trytond/tests/test_importdata.py
@@ -4,442 +4,473 @@
 import unittest
 from decimal import InvalidOperation
 
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.exceptions import UserError
 
 
 class ImportDataTestCase(unittest.TestCase):
     'Test import_data'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.boolean = POOL.get('test.import_data.boolean')
-        self.integer = POOL.get('test.import_data.integer')
-        self.integer_required = POOL.get('test.import_data.integer_required')
-        self.float = POOL.get('test.import_data.float')
-        self.float_required = POOL.get('test.import_data.float_required')
-        self.numeric = POOL.get('test.import_data.numeric')
-        self.numeric_required = POOL.get('test.import_data.numeric_required')
-        self.char = POOL.get('test.import_data.char')
-        self.text = POOL.get('test.import_data.text')
-        self.date = POOL.get('test.import_data.date')
-        self.datetime = POOL.get('test.import_data.datetime')
-        self.selection = POOL.get('test.import_data.selection')
-        self.many2one = POOL.get('test.import_data.many2one')
-        self.many2many = POOL.get('test.import_data.many2many')
-        self.one2many = POOL.get('test.import_data.one2many')
-        self.reference = POOL.get('test.import_data.reference')
-
-    def test0010boolean(self):
+
+    @with_transaction()
+    def test_boolean(self):
         'Test boolean'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['True']]), 1)
+        pool = Pool()
+        Boolean = pool.get('test.import_data.boolean')
+
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['True']]), 1)
 
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['1']]), 1)
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['1']]), 1)
 
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['False']]), 1)
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['False']]), 1)
 
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['0']]), 1)
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['0']]), 1)
 
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['']]), 1)
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['']]), 1)
 
-            self.assertEqual(self.boolean.import_data(['boolean'],
-                [['True'], ['False']]), 2)
+        self.assertEqual(Boolean.import_data(['boolean'],
+            [['True'], ['False']]), 2)
 
-            self.assertRaises(ValueError, self.boolean.import_data,
-                ['boolean'], [['foo']])
+        self.assertRaises(ValueError, Boolean.import_data,
+            ['boolean'], [['foo']])
 
-    def test0020integer(self):
+    @with_transaction()
+    def test_integer(self):
         'Test integer'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.integer.import_data(['integer'],
-                [['1']]), 1)
+        pool = Pool()
+        Integer = pool.get('test.import_data.integer')
+
+        self.assertEqual(Integer.import_data(['integer'],
+            [['1']]), 1)
 
-            self.assertEqual(self.integer.import_data(['integer'],
-                [['-1']]), 1)
+        self.assertEqual(Integer.import_data(['integer'],
+            [['-1']]), 1)
 
-            self.assertEqual(self.integer.import_data(['integer'],
-                [['']]), 1)
+        self.assertEqual(Integer.import_data(['integer'],
+            [['']]), 1)
 
-            self.assertEqual(self.integer.import_data(['integer'],
-                [['1'], ['2']]), 2)
+        self.assertEqual(Integer.import_data(['integer'],
+            [['1'], ['2']]), 2)
 
-            self.assertRaises(ValueError, self.integer.import_data,
-                ['integer'], [['1.1']])
+        self.assertRaises(ValueError, Integer.import_data,
+            ['integer'], [['1.1']])
 
-            self.assertRaises(ValueError, self.integer.import_data,
-                ['integer'], [['-1.1']])
+        self.assertRaises(ValueError, Integer.import_data,
+            ['integer'], [['-1.1']])
 
-            self.assertRaises(ValueError, self.integer.import_data,
-                ['integer'], [['foo']])
+        self.assertRaises(ValueError, Integer.import_data,
+            ['integer'], [['foo']])
 
-            self.assertEqual(self.integer.import_data(['integer'],
-                [['0']]), 1)
+        self.assertEqual(Integer.import_data(['integer'],
+            [['0']]), 1)
 
-    def test0021integer_required(self):
+    @with_transaction()
+    def test_integer_required(self):
         'Test required integer'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.integer_required.import_data(['integer'],
-                [['1']]), 1)
+        pool = Pool()
+        IntegerRequired = pool.get('test.import_data.integer_required')
+        transaction = Transaction()
 
-            self.assertEqual(self.integer_required.import_data(['integer'],
-                [['-1']]), 1)
+        self.assertEqual(IntegerRequired.import_data(['integer'],
+            [['1']]), 1)
 
-            self.assertRaises(UserError, self.integer_required.import_data,
-                ['integer'], [['']])
-            transaction.cursor.rollback()
+        self.assertEqual(IntegerRequired.import_data(['integer'],
+            [['-1']]), 1)
 
-            self.assertEqual(self.integer_required.import_data(['integer'],
-                [['1'], ['2']]), 2)
+        self.assertRaises(UserError, IntegerRequired.import_data,
+            ['integer'], [['']])
+        transaction.rollback()
 
-            self.assertRaises(ValueError, self.integer_required.import_data,
-                ['integer'], [['1.1']])
+        self.assertEqual(IntegerRequired.import_data(['integer'],
+            [['1'], ['2']]), 2)
 
-            self.assertRaises(ValueError, self.integer_required.import_data,
-                ['integer'], [['-1.1']])
+        self.assertRaises(ValueError, IntegerRequired.import_data,
+            ['integer'], [['1.1']])
 
-            self.assertRaises(ValueError, self.integer_required.import_data,
-                ['integer'], [['foo']])
+        self.assertRaises(ValueError, IntegerRequired.import_data,
+            ['integer'], [['-1.1']])
 
-            self.assertEqual(self.integer_required.import_data(['integer'],
-                [['0']]), 1)
+        self.assertRaises(ValueError, IntegerRequired.import_data,
+            ['integer'], [['foo']])
 
-    def test0030float(self):
+        self.assertEqual(IntegerRequired.import_data(['integer'],
+            [['0']]), 1)
+
+    @with_transaction()
+    def test_float(self):
         'Test float'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.float.import_data(['float'],
-                [['1.1']]), 1)
+        pool = Pool()
+        Float = pool.get('test.import_data.float')
+
+        self.assertEqual(Float.import_data(['float'],
+            [['1.1']]), 1)
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['-1.1']]), 1)
+        self.assertEqual(Float.import_data(['float'],
+            [['-1.1']]), 1)
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['1']]), 1)
+        self.assertEqual(Float.import_data(['float'],
+            [['1']]), 1)
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['']]), 1)
+        self.assertEqual(Float.import_data(['float'],
+            [['']]), 1)
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['1.1'], ['2.2']]), 2)
+        self.assertEqual(Float.import_data(['float'],
+            [['1.1'], ['2.2']]), 2)
 
-            self.assertRaises(ValueError, self.float.import_data,
-                ['float'], [['foo']])
+        self.assertRaises(ValueError, Float.import_data,
+            ['float'], [['foo']])
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['0']]), 1)
+        self.assertEqual(Float.import_data(['float'],
+            [['0']]), 1)
 
-            self.assertEqual(self.float.import_data(['float'],
-                [['0.0']]), 1)
+        self.assertEqual(Float.import_data(['float'],
+            [['0.0']]), 1)
 
-    def test0031float_required(self):
+    @with_transaction()
+    def test_float_required(self):
         'Test required float'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['1.1']]), 1)
+        pool = Pool()
+        FloatRequired = pool.get('test.import_data.float_required')
+        transaction = Transaction()
+
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['1.1']]), 1)
 
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['-1.1']]), 1)
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['-1.1']]), 1)
 
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['1']]), 1)
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['1']]), 1)
 
-            self.assertRaises(UserError, self.float_required.import_data,
-                ['float'], [['']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, FloatRequired.import_data,
+            ['float'], [['']])
+        transaction.rollback()
 
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['1.1'], ['2.2']]), 2)
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['1.1'], ['2.2']]), 2)
 
-            self.assertRaises(ValueError, self.float_required.import_data,
-                ['float'], [['foo']])
+        self.assertRaises(ValueError, FloatRequired.import_data,
+            ['float'], [['foo']])
 
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['0']]), 1)
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['0']]), 1)
 
-            self.assertEqual(self.float_required.import_data(['float'],
-                [['0.0']]), 1)
+        self.assertEqual(FloatRequired.import_data(['float'],
+            [['0.0']]), 1)
 
-    def test0040numeric(self):
+    @with_transaction()
+    def test_numeric(self):
         'Test numeric'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['1.1']]), 1)
+        pool = Pool()
+        Numeric = pool.get('test.import_data.numeric')
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['-1.1']]), 1)
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['1.1']]), 1)
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['1']]), 1)
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['-1.1']]), 1)
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['']]), 1)
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['1']]), 1)
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['1.1'], ['2.2']]), 2)
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['']]), 1)
 
-            self.assertRaises(InvalidOperation, self.numeric.import_data,
-                ['numeric'], [['foo']])
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['1.1'], ['2.2']]), 2)
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['0']]), 1)
+        self.assertRaises(InvalidOperation, Numeric.import_data,
+            ['numeric'], [['foo']])
 
-            self.assertEqual(self.numeric.import_data(['numeric'],
-                [['0.0']]), 1)
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['0']]), 1)
 
-    def test0041numeric_required(self):
+        self.assertEqual(Numeric.import_data(['numeric'],
+            [['0.0']]), 1)
+
+    @with_transaction()
+    def test_numeric_required(self):
         'Test required numeric'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['1.1']]), 1)
+        pool = Pool()
+        NumericRequired = pool.get('test.import_data.numeric_required')
+        transaction = Transaction()
+
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['1.1']]), 1)
 
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['-1.1']]), 1)
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['-1.1']]), 1)
 
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['1']]), 1)
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['1']]), 1)
 
-            self.assertRaises(UserError, self.numeric_required.import_data,
-                ['numeric'], [['']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, NumericRequired.import_data,
+            ['numeric'], [['']])
+        transaction.rollback()
 
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['1.1'], ['2.2']]), 2)
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['1.1'], ['2.2']]), 2)
 
-            self.assertRaises(InvalidOperation,
-                self.numeric_required.import_data, ['numeric'], [['foo']])
+        self.assertRaises(InvalidOperation,
+            NumericRequired.import_data, ['numeric'], [['foo']])
 
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['0']]), 1)
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['0']]), 1)
 
-            self.assertEqual(self.numeric_required.import_data(['numeric'],
-                [['0.0']]), 1)
+        self.assertEqual(NumericRequired.import_data(['numeric'],
+            [['0.0']]), 1)
 
-    def test0050char(self):
+    @with_transaction()
+    def test_char(self):
         'Test char'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.char.import_data(['char'],
-                [['test']]), 1)
+        pool = Pool()
+        Char = pool.get('test.import_data.char')
+
+        self.assertEqual(Char.import_data(['char'],
+            [['test']]), 1)
 
-            self.assertEqual(self.char.import_data(['char'],
-                [['']]), 1)
+        self.assertEqual(Char.import_data(['char'],
+            [['']]), 1)
 
-            self.assertEqual(self.char.import_data(['char'],
-                [['test'], ['foo'], ['bar']]), 3)
+        self.assertEqual(Char.import_data(['char'],
+            [['test'], ['foo'], ['bar']]), 3)
 
-    def test0060text(self):
+    @with_transaction()
+    def test_text(self):
         'Test text'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.text.import_data(['text'],
-                [['test']]), 1)
+        pool = Pool()
+        Text = pool.get('test.import_data.text')
 
-            self.assertEqual(self.text.import_data(['text'],
-                [['']]), 1)
+        self.assertEqual(Text.import_data(['text'],
+            [['test']]), 1)
 
-            self.assertEqual(self.text.import_data(['text'],
-                [['test'], ['foo'], ['bar']]), 3)
+        self.assertEqual(Text.import_data(['text'],
+            [['']]), 1)
 
-    def test0080date(self):
+        self.assertEqual(Text.import_data(['text'],
+            [['test'], ['foo'], ['bar']]), 3)
+
+    @with_transaction()
+    def test_date(self):
         'Test date'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.date.import_data(['date'],
-                [['2010-01-01']]), 1)
+        pool = Pool()
+        Date = pool.get('test.import_data.date')
+
+        self.assertEqual(Date.import_data(['date'],
+            [['2010-01-01']]), 1)
 
-            self.assertEqual(self.date.import_data(['date'],
-                [['']]), 1)
+        self.assertEqual(Date.import_data(['date'],
+            [['']]), 1)
 
-            self.assertEqual(self.date.import_data(['date'],
-                [['2010-01-01'], ['2010-02-01']]), 2)
+        self.assertEqual(Date.import_data(['date'],
+            [['2010-01-01'], ['2010-02-01']]), 2)
 
-            self.assertRaises(ValueError, self.date.import_data,
-                ['date'], [['foo']])
+        self.assertRaises(ValueError, Date.import_data,
+            ['date'], [['foo']])
 
-    def test0090datetime(self):
+    @with_transaction()
+    def test_datetime(self):
         'Test datetime'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.datetime.import_data(['datetime'],
-                [['2010-01-01 12:00:00']]), 1)
+        pool = Pool()
+        Datetime = pool.get('test.import_data.datetime')
 
-            self.assertEqual(self.datetime.import_data(['datetime'],
-                [['']]), 1)
+        self.assertEqual(Datetime.import_data(['datetime'],
+            [['2010-01-01 12:00:00']]), 1)
 
-            self.assertEqual(self.datetime.import_data(['datetime'],
-                [['2010-01-01 12:00:00'], ['2010-01-01 13:30:00']]), 2)
+        self.assertEqual(Datetime.import_data(['datetime'],
+            [['']]), 1)
 
-            self.assertRaises(ValueError, self.datetime.import_data,
-                ['datetime'], [['foo']])
+        self.assertEqual(Datetime.import_data(['datetime'],
+            [['2010-01-01 12:00:00'], ['2010-01-01 13:30:00']]), 2)
 
-    def test0100selection(self):
+        self.assertRaises(ValueError, Datetime.import_data,
+            ['datetime'], [['foo']])
+
+    @with_transaction()
+    def test_selection(self):
         'Test selection'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.selection.import_data(['selection'],
-                [['select1']]), 1)
+        pool = Pool()
+        Selection = pool.get('test.import_data.selection')
+
+        self.assertEqual(Selection.import_data(['selection'],
+            [['select1']]), 1)
 
-            self.assertEqual(self.selection.import_data(['selection'],
-                [['']]), 1)
+        self.assertEqual(Selection.import_data(['selection'],
+            [['']]), 1)
 
-            self.assertEqual(self.selection.import_data(['selection'],
-                [['select1'], ['select2']]), 2)
+        self.assertEqual(Selection.import_data(['selection'],
+            [['select1'], ['select2']]), 2)
 
-            self.assertRaises(UserError, self.selection.import_data,
-                ['selection'], [['foo']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Selection.import_data,
+            ['selection'], [['foo']])
 
-    def test0110many2one(self):
+    @with_transaction()
+    def test_many2one(self):
         'Test many2one'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.many2one.import_data(['many2one'],
-                [['Test']]), 1)
+        pool = Pool()
+        Many2one = pool.get('test.import_data.many2one')
+        transaction = Transaction()
+
+        self.assertEqual(Many2one.import_data(['many2one'],
+            [['Test']]), 1)
 
-            self.assertEqual(self.many2one.import_data(['many2one:id'],
-                [['tests.import_data_many2one_target_test']]), 1)
+        self.assertEqual(Many2one.import_data(['many2one:id'],
+            [['tests.import_data_many2one_target_test']]), 1)
 
-            self.assertEqual(self.many2one.import_data(['many2one'],
-                [['']]), 1)
+        self.assertEqual(Many2one.import_data(['many2one'],
+            [['']]), 1)
 
-            self.assertEqual(self.many2one.import_data(['many2one'],
-                [['Test'], ['Test']]), 2)
+        self.assertEqual(Many2one.import_data(['many2one'],
+            [['Test'], ['Test']]), 2)
 
-            self.assertRaises(UserError, self.many2one.import_data,
-                ['many2one'], [['foo']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2one.import_data,
+            ['many2one'], [['foo']])
+        transaction.rollback()
 
-            self.assertRaises(UserError, self.many2one.import_data,
-                ['many2one'], [['Duplicate']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2one.import_data,
+            ['many2one'], [['Duplicate']])
+        transaction.rollback()
 
-            self.assertRaises(UserError, self.many2one.import_data,
-                ['many2one:id'], [['foo']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2one.import_data,
+            ['many2one:id'], [['foo']])
+        transaction.rollback()
 
-            self.assertRaises(Exception, self.many2one.import_data,
-                ['many2one:id'], [['tests.foo']])
-            transaction.cursor.rollback()
+        self.assertRaises(Exception, Many2one.import_data,
+            ['many2one:id'], [['tests.foo']])
+        transaction.rollback()
 
-    def test0120many2many(self):
+    @with_transaction()
+    def test_many2many(self):
         'Test many2many'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['Test 1']]), 1)
+        pool = Pool()
+        Many2many = pool.get('test.import_data.many2many')
+        transaction = Transaction()
 
-            self.assertEqual(self.many2many.import_data(['many2many:id'],
-                [['tests.import_data_many2many_target_test1']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['Test 1']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['Test 1,Test 2']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many:id'],
+            [['tests.import_data_many2many_target_test1']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many:id'],
-                [['tests.import_data_many2many_target_test1,'
-                    'tests.import_data_many2many_target_test2']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['Test 1,Test 2']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['Test\, comma']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many:id'],
+            [['tests.import_data_many2many_target_test1,'
+                'tests.import_data_many2many_target_test2']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['Test\, comma,Test 1']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['Test\, comma']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['']]), 1)
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['Test\, comma,Test 1']]), 1)
 
-            self.assertEqual(self.many2many.import_data(['many2many'],
-                [['Test 1'], ['Test 2']]), 2)
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['']]), 1)
 
-            self.assertRaises(UserError, self.many2many.import_data,
-                ['many2many'], [['foo']])
-            transaction.cursor.rollback()
+        self.assertEqual(Many2many.import_data(['many2many'],
+            [['Test 1'], ['Test 2']]), 2)
 
-            self.assertRaises(UserError, self.many2many.import_data,
-                ['many2many'], [['Test 1,foo']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2many.import_data,
+            ['many2many'], [['foo']])
+        transaction.rollback()
 
-            self.assertRaises(UserError, self.many2many.import_data,
-                ['many2many'], [['Duplicate']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2many.import_data,
+            ['many2many'], [['Test 1,foo']])
+        transaction.rollback()
 
-            self.assertRaises(UserError, self.many2many.import_data,
-                ['many2many'], [['Test 1,Duplicate']])
-            transaction.cursor.rollback()
+        self.assertRaises(UserError, Many2many.import_data,
+            ['many2many'], [['Duplicate']])
+        transaction.rollback()
 
-    def test0130one2many(self):
+        self.assertRaises(UserError, Many2many.import_data,
+            ['many2many'], [['Test 1,Duplicate']])
+        transaction.rollback()
+
+    @with_transaction()
+    def test_one2many(self):
         'Test one2many'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.one2many.import_data(
-                    ['name', 'one2many/name'], [['Test', 'Test 1']]), 1)
-
-            self.assertEqual(self.one2many.import_data(
-                    ['name', 'one2many/name'],
-                    [['Test', 'Test 1'], ['', 'Test 2']]), 1)
-
-            self.assertEqual(self.one2many.import_data(
-                    ['name', 'one2many/name'],
-                    [
-                        ['Test 1', 'Test 1'],
-                        ['', 'Test 2'],
-                        ['Test 2', 'Test 1']]), 2)
-
-    def test0140reference(self):
-        'Test reference'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.assertEqual(self.reference.import_data(['reference'],
-                [['test.import_data.reference.selection,Test']]), 1)
-            reference, = self.reference.search([])
-            self.assertEqual(reference.reference.__name__,
-                'test.import_data.reference.selection')
-            transaction.cursor.rollback()
+        pool = Pool()
+        One2many = pool.get('test.import_data.one2many')
+
+        self.assertEqual(One2many.import_data(
+                ['name', 'one2many/name'], [['Test', 'Test 1']]), 1)
+
+        self.assertEqual(One2many.import_data(
+                ['name', 'one2many/name'],
+                [['Test', 'Test 1'], ['', 'Test 2']]), 1)
 
-            self.assertEqual(self.reference.import_data(['reference:id'],
-                [['test.import_data.reference.selection,'
-                    'tests.import_data_reference_selection_test']]), 1)
-            reference, = self.reference.search([])
+        self.assertEqual(One2many.import_data(
+                ['name', 'one2many/name'],
+                [
+                    ['Test 1', 'Test 1'],
+                    ['', 'Test 2'],
+                    ['Test 2', 'Test 1']]), 2)
+
+    @with_transaction()
+    def test_reference(self):
+        'Test reference'
+        pool = Pool()
+        Reference = pool.get('test.import_data.reference')
+        transaction = Transaction()
+
+        self.assertEqual(Reference.import_data(['reference'],
+            [['test.import_data.reference.selection,Test']]), 1)
+        reference, = Reference.search([])
+        self.assertEqual(reference.reference.__name__,
+            'test.import_data.reference.selection')
+        transaction.rollback()
+
+        self.assertEqual(Reference.import_data(['reference:id'],
+            [['test.import_data.reference.selection,'
+                'tests.import_data_reference_selection_test']]), 1)
+        reference, = Reference.search([])
+        self.assertEqual(reference.reference.__name__,
+            'test.import_data.reference.selection')
+        transaction.rollback()
+
+        self.assertEqual(Reference.import_data(['reference'],
+            [['']]), 1)
+        reference, = Reference.search([])
+        self.assertEqual(reference.reference, None)
+        transaction.rollback()
+
+        self.assertEqual(Reference.import_data(['reference'],
+            [['test.import_data.reference.selection,Test'],
+                ['test.import_data.reference.selection,Test']]), 2)
+        for reference in Reference.search([]):
             self.assertEqual(reference.reference.__name__,
                 'test.import_data.reference.selection')
-            transaction.cursor.rollback()
-
-            self.assertEqual(self.reference.import_data(['reference'],
-                [['']]), 1)
-            reference, = self.reference.search([])
-            self.assertEqual(reference.reference, None)
-            transaction.cursor.rollback()
-
-            self.assertEqual(self.reference.import_data(['reference'],
-                [['test.import_data.reference.selection,Test'],
-                    ['test.import_data.reference.selection,Test']]), 2)
-            for reference in self.reference.search([]):
-                self.assertEqual(reference.reference.__name__,
-                    'test.import_data.reference.selection')
-            transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.reference.import_data,
-                ['reference'], [['test.import_data.reference.selection,foo']])
-            transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.reference.import_data,
-                ['reference'],
-                [['test.import_data.reference.selection,Duplicate']])
-            transaction.cursor.rollback()
-
-            self.assertRaises(UserError, self.reference.import_data,
-                ['reference:id'],
-                [['test.import_data.reference.selection,foo']])
-            transaction.cursor.rollback()
-
-            self.assertRaises(Exception, self.reference.import_data,
-                ['reference:id'],
-                [['test.import_data.reference.selection,test.foo']])
-            transaction.cursor.rollback()
+        transaction.rollback()
+
+        self.assertRaises(UserError, Reference.import_data,
+            ['reference'], [['test.import_data.reference.selection,foo']])
+        transaction.rollback()
+
+        self.assertRaises(UserError, Reference.import_data,
+            ['reference'],
+            [['test.import_data.reference.selection,Duplicate']])
+        transaction.rollback()
+
+        self.assertRaises(UserError, Reference.import_data,
+            ['reference:id'],
+            [['test.import_data.reference.selection,foo']])
+        transaction.rollback()
+
+        self.assertRaises(Exception, Reference.import_data,
+            ['reference:id'],
+            [['test.import_data.reference.selection,test.foo']])
+        transaction.rollback()
 
 
 def suite():
diff --git a/trytond/tests/test_mixins.py b/trytond/tests/test_mixins.py
index 087e40d..a65f36a 100644
--- a/trytond/tests/test_mixins.py
+++ b/trytond/tests/test_mixins.py
@@ -5,38 +5,44 @@
 import unittest
 import urllib
 
-from trytond.tests.test_tryton import (POOL, DB_NAME, USER, CONTEXT,
-    install_module)
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.url import HOSTNAME
 
 
 class UrlTestCase(unittest.TestCase):
     "Test URL generation"
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.urlmodel = POOL.get('test.urlobject')
-        self.urlwizard = POOL.get('test.test_wizard', type='wizard')
-        self.hostname = HOSTNAME
 
+    @with_transaction()
     def testModelURL(self):
         "Test model URLs"
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.urlmodel.__url__,
-                'tryton://%s/%s/model/test.urlobject' % (self.hostname,
-                    urllib.quote(DB_NAME)))
+        pool = Pool()
+        UrlObject = pool.get('test.urlobject')
+        db_name = Transaction().database.name
 
-            self.assertEqual(self.urlmodel(1).__url__,
-                'tryton://%s/%s/model/test.urlobject/1' % (self.hostname,
-                    urllib.quote(DB_NAME)))
+        self.assertEqual(UrlObject.__url__,
+            'tryton://%s/%s/model/test.urlobject' % (
+                HOSTNAME, urllib.quote(db_name)))
 
+        self.assertEqual(UrlObject(1).__url__,
+            'tryton://%s/%s/model/test.urlobject/1' % (
+                HOSTNAME, urllib.quote(db_name)))
+
+    @with_transaction()
     def testWizardURL(self):
         "Test wizard URLs"
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            self.assertEqual(self.urlwizard.__url__,
-                'tryton://%s/%s/wizard/test.test_wizard' % (self.hostname,
-                    urllib.quote(DB_NAME)))
+        pool = Pool()
+        UrlWizard = pool.get('test.test_wizard', type='wizard')
+        db_name = Transaction().database.name
+
+        self.assertEqual(UrlWizard.__url__,
+            'tryton://%s/%s/wizard/test.test_wizard' % (
+                HOSTNAME, urllib.quote(db_name)))
 
 
 def suite():
diff --git a/trytond/tests/test_modelsingleton.py b/trytond/tests/test_modelsingleton.py
index 014c80e..bd581b6 100644
--- a/trytond/tests/test_modelsingleton.py
+++ b/trytond/tests/test_modelsingleton.py
@@ -3,130 +3,131 @@
 # this repository contains the full copyright notices and license terms.
 import unittest
 from datetime import datetime
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 
 
 class ModelSingletonTestCase(unittest.TestCase):
     'Test ModelSingleton'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.singleton = POOL.get('test.singleton')
 
-    def test0010read(self):
+    @with_transaction()
+    def test_read(self):
         'Test read method'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            singleton, = self.singleton.read([1], ['name'])
-            self.assert_(singleton['name'] == 'test')
-            self.assert_(singleton['id'] == 1)
-
-            singleton, = self.singleton.read([1], ['name'])
-            self.assert_(singleton['name'] == 'test')
-            self.assert_(singleton['id'] == 1)
-
-            singleton, = self.singleton.read([1], [
-                'create_uid',
-                'create_uid.rec_name',
-                'create_date',
-                'write_uid',
-                'write_date',
-                ])
-            self.assertEqual(singleton['create_uid'], USER)
-            self.assertEqual(singleton['create_uid.rec_name'], 'Administrator')
-            self.assert_(isinstance(singleton['create_date'], datetime))
-            self.assertEqual(singleton['write_uid'], None)
-            self.assertEqual(singleton['write_date'], None)
-
-            transaction.cursor.rollback()
-
-    def test0020create(self):
+        pool = Pool()
+        Singleton = pool.get('test.singleton')
+
+        singleton, = Singleton.read([1], ['name'])
+        self.assert_(singleton['name'] == 'test')
+        self.assert_(singleton['id'] == 1)
+
+        singleton, = Singleton.read([1], ['name'])
+        self.assert_(singleton['name'] == 'test')
+        self.assert_(singleton['id'] == 1)
+
+        singleton, = Singleton.read([1], [
+            'create_uid',
+            'create_uid.rec_name',
+            'create_date',
+            'write_uid',
+            'write_date',
+            ])
+        self.assertEqual(singleton['create_uid'], Transaction().user)
+        self.assertEqual(singleton['create_uid.rec_name'], 'Administrator')
+        self.assert_(isinstance(singleton['create_date'], datetime))
+        self.assertEqual(singleton['write_uid'], None)
+        self.assertEqual(singleton['write_date'], None)
+
+    @with_transaction()
+    def test_create(self):
         'Test create method'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            singleton, = self.singleton.create([{'name': 'bar'}])
-            self.assert_(singleton)
-            self.assertEqual(singleton.name, 'bar')
+        pool = Pool()
+        Singleton = pool.get('test.singleton')
 
-            singleton2, = self.singleton.create([{'name': 'foo'}])
-            self.assertEqual(singleton2, singleton)
+        singleton, = Singleton.create([{'name': 'bar'}])
+        self.assert_(singleton)
+        self.assertEqual(singleton.name, 'bar')
 
-            self.assertEqual(singleton.name, 'foo')
+        singleton2, = Singleton.create([{'name': 'foo'}])
+        self.assertEqual(singleton2, singleton)
 
-            singletons = self.singleton.search([])
-            self.assertEqual(singletons, [singleton])
+        self.assertEqual(singleton.name, 'foo')
 
-            transaction.cursor.rollback()
+        singletons = Singleton.search([])
+        self.assertEqual(singletons, [singleton])
 
-    def test0030copy(self):
+    @with_transaction()
+    def test_copy(self):
         'Test copy method'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            singleton, = self.singleton.search([])
+        pool = Pool()
+        Singleton = pool.get('test.singleton')
 
-            singleton2, = self.singleton.copy([singleton])
-            self.assertEqual(singleton2, singleton)
+        singleton, = Singleton.search([])
 
-            singletons = self.singleton.search([])
-            self.assertEqual(len(singletons), 1)
+        singleton2, = Singleton.copy([singleton])
+        self.assertEqual(singleton2, singleton)
 
-            singleton3, = self.singleton.copy([singleton], {'name': 'bar'})
-            self.assertEqual(singleton3, singleton)
+        singletons = Singleton.search([])
+        self.assertEqual(len(singletons), 1)
 
-            singletons = self.singleton.search([])
-            self.assertEqual(len(singletons), 1)
+        singleton3, = Singleton.copy([singleton], {'name': 'bar'})
+        self.assertEqual(singleton3, singleton)
 
-            transaction.cursor.rollback()
+        singletons = Singleton.search([])
+        self.assertEqual(len(singletons), 1)
 
-    def test0040default_get(self):
+    @with_transaction()
+    def test_default_get(self):
         'Test default_get method'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            default = self.singleton.default_get(['name'])
-            self.assertEqual(default, {'name': 'test'})
+        pool = Pool()
+        Singleton = pool.get('test.singleton')
 
-            default = self.singleton.default_get(['create_uid'])
-            self.assertEqual(len(default), 2)
+        default = Singleton.default_get(['name'])
+        self.assertEqual(default, {'name': 'test'})
 
-            default = self.singleton.default_get(['create_uid'],
-                    with_rec_name=False)
-            self.assertEqual(len(default), 1)
+        default = Singleton.default_get(['create_uid'])
+        self.assertEqual(len(default), 2)
 
-            self.singleton.create([{'name': 'bar'}])
+        default = Singleton.default_get(['create_uid'],
+                with_rec_name=False)
+        self.assertEqual(len(default), 1)
 
-            default = self.singleton.default_get(['name'])
-            self.assertEqual(default, {'name': 'bar'})
+        Singleton.create([{'name': 'bar'}])
 
-            default = self.singleton.default_get(['create_uid'])
-            self.assertEqual(len(default), 2)
+        default = Singleton.default_get(['name'])
+        self.assertEqual(default, {'name': 'bar'})
 
-            default = self.singleton.default_get(['create_uid'],
-                    with_rec_name=False)
-            self.assertEqual(len(default), 1)
+        default = Singleton.default_get(['create_uid'])
+        self.assertEqual(len(default), 2)
 
-            transaction.cursor.rollback()
+        default = Singleton.default_get(['create_uid'],
+                with_rec_name=False)
+        self.assertEqual(len(default), 1)
 
-    def test0050search(self):
+    @with_transaction()
+    def test_search(self):
         'Test search method'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            singletons = self.singleton.search([])
-            self.assertEqual(map(int, singletons), [1])
-
-            singletons = self.singleton.search([])
-            self.assertEqual(map(int, singletons), [1])
-
-            count = self.singleton.search([], count=True)
-            self.assertEqual(count, 1)
-
-            self.singleton.create([{'name': 'foo'}])
-            singleton, = self.singleton.search([('name', '=', 'foo')])
-            self.assertEqual(singleton.name, 'foo')
-            singletons = self.singleton.search([('name', '=', 'bar')])
-            self.assertEqual(singletons, [])
-            transaction.cursor.rollback()
+        pool = Pool()
+        Singleton = pool.get('test.singleton')
+
+        singletons = Singleton.search([])
+        self.assertEqual(map(int, singletons), [1])
+
+        singletons = Singleton.search([])
+        self.assertEqual(map(int, singletons), [1])
+
+        count = Singleton.search([], count=True)
+        self.assertEqual(count, 1)
+
+        Singleton.create([{'name': 'foo'}])
+        singleton, = Singleton.search([('name', '=', 'foo')])
+        self.assertEqual(singleton.name, 'foo')
+        singletons = Singleton.search([('name', '=', 'bar')])
+        self.assertEqual(singletons, [])
 
 
 def suite():
diff --git a/trytond/tests/test_modelsql.py b/trytond/tests/test_modelsql.py
index e9ea26d..7c47414 100644
--- a/trytond/tests/test_modelsql.py
+++ b/trytond/tests/test_modelsql.py
@@ -5,76 +5,114 @@
 import unittest
 import time
 
+from mock import patch, call
+
 from trytond import backend
 from trytond.exceptions import UserError, ConcurrencyException
 from trytond.transaction import Transaction
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-    install_module
+from trytond.pool import Pool
+from trytond.tests.test_tryton import install_module, with_transaction
 
 
 class ModelSQLTestCase(unittest.TestCase):
     'Test ModelSQL'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.modelsql = POOL.get('test.modelsql')
-        self.modelsql_timestamp = POOL.get('test.modelsql.timestamp')
 
     @unittest.skipIf(backend.name() == 'sqlite',
         'SQLite not concerned because tryton don\'t set "NOT NULL"'
         'constraint: "ALTER TABLE" don\'t support NOT NULL constraint'
         'without default value')
-    def test0010required_field_missing(self):
+    @with_transaction()
+    def test_required_field_missing(self):
         'Test error message when a required field is missing'
+        pool = Pool()
+        Modelsql = pool.get('test.modelsql')
+        transaction = Transaction()
+
         fields = {
             'desc': '',
             'integer': 0,
             }
         for key, value in fields.iteritems():
-            with Transaction().start(DB_NAME, USER, context=CONTEXT):
-                try:
-                    self.modelsql.create([{key: value}])
-                except UserError, err:
-                    # message must not quote key
-                    msg = "'%s' not missing but quoted in error: '%s'" % (key,
-                            err.message)
-                    self.assertTrue(key not in err.message, msg)
-                    continue
+            try:
+                Modelsql.create([{key: value}])
+            except UserError, err:
+                # message must not quote key
+                msg = "'%s' not missing but quoted in error: '%s'" % (key,
+                        err.message)
+                self.assertTrue(key not in err.message, msg)
+            else:
                 self.fail('UserError should be caught')
+            transaction.rollback()
 
-    def test0020check_timestamp(self):
+    @with_transaction()
+    def test_check_timestamp(self):
         'Test check timestamp'
-        # cursor must be committed between each changes otherwise NOW() returns
-        # always the same timestamp.
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            cursor = transaction.cursor
-            record, = self.modelsql_timestamp.create([{}])
-            cursor.commit()
-
-            timestamp = self.modelsql_timestamp.read([record.id],
-                ['_timestamp'])[0]['_timestamp']
-
-            if backend.name() in ('sqlite', 'mysql'):
-                # timestamp precision of sqlite is the second
-                time.sleep(1)
-
-            self.modelsql_timestamp.write([record], {})
-            cursor.commit()
-
-            transaction.timestamp[str(record)] = timestamp
-            self.assertRaises(ConcurrencyException,
-                self.modelsql_timestamp.write, [record], {})
-
-            transaction.timestamp[str(record)] = timestamp
-            self.assertRaises(ConcurrencyException,
-                self.modelsql_timestamp.delete, [record])
-
-            transaction.timestamp.pop(str(record), None)
-            self.modelsql_timestamp.write([record], {})
-            cursor.commit()
-            self.modelsql_timestamp.delete([record])
-            cursor.commit()
+        pool = Pool()
+        ModelsqlTimestamp = pool.get('test.modelsql.timestamp')
+        transaction = Transaction()
+        # transaction must be committed between each changes otherwise NOW()
+        # returns always the same timestamp.
+        record, = ModelsqlTimestamp.create([{}])
+        transaction.commit()
+
+        timestamp = ModelsqlTimestamp.read([record.id],
+            ['_timestamp'])[0]['_timestamp']
+
+        if backend.name() in ('sqlite', 'mysql'):
+            # timestamp precision of sqlite is the second
+            time.sleep(1)
+
+        ModelsqlTimestamp.write([record], {})
+        transaction.commit()
+
+        transaction.timestamp[str(record)] = timestamp
+        self.assertRaises(ConcurrencyException,
+            ModelsqlTimestamp.write, [record], {})
+
+        transaction.timestamp[str(record)] = timestamp
+        self.assertRaises(ConcurrencyException,
+            ModelsqlTimestamp.delete, [record])
+
+        transaction.timestamp.pop(str(record), None)
+        ModelsqlTimestamp.write([record], {})
+        transaction.commit()
+        ModelsqlTimestamp.delete([record])
+        transaction.commit()
+
+    @with_transaction()
+    def test_create_field_set(self):
+        'Test field.set in create'
+        pool = Pool()
+        Model = pool.get('test.modelsql.field_set')
+
+        with patch.object(Model, 'set_field') as setter:
+            records = Model.create([{'field': 1}])
+            setter.assert_called_with(records, 'field', 1)
+
+        # Different values are not grouped
+        with patch.object(Model, 'set_field') as setter:
+            records = Model.create([{'field': 1}, {'field': 2}])
+            setter.assert_has_calls([
+                    call([records[0]], 'field', 1),
+                    call([records[1]], 'field', 2),
+                    ])
+
+        # Same values are grouped in one call
+        with patch.object(Model, 'set_field') as setter:
+            records = Model.create([{'field': 1}, {'field': 1}])
+            setter.assert_called_with(records, 'field', 1)
+
+        # Mixed values are grouped per value
+        with patch.object(Model, 'set_field') as setter:
+            records = Model.create([{'field': 1}, {'field': 2}, {'field': 1}])
+            setter.assert_has_calls([
+                    call([records[0], records[2]], 'field', 1),
+                    call([records[1]], 'field', 2),
+                    ])
 
 
 def suite():
diff --git a/trytond/tests/test_modelstorage.py b/trytond/tests/test_modelstorage.py
index 1be6597..6ce7839 100644
--- a/trytond/tests/test_modelstorage.py
+++ b/trytond/tests/test_modelstorage.py
@@ -3,36 +3,36 @@
 
 import unittest
 
-from trytond.transaction import Transaction
 from trytond.pool import Pool
-from trytond.tests.test_tryton import DB_NAME, USER, CONTEXT, install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 
 
 class ModelStorageTestCase(unittest.TestCase):
     'Test ModelStorage'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
+    @with_transaction()
     def test_search_read_order(self):
         'Test search_read order'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            pool = Pool()
-            ModelStorage = pool.get('test.modelstorage')
+        pool = Pool()
+        ModelStorage = pool.get('test.modelstorage')
 
-            ModelStorage.create([{'name': i} for i in ['foo', 'bar', 'test']])
+        ModelStorage.create([{'name': i} for i in ['foo', 'bar', 'test']])
 
-            rows = ModelStorage.search_read([])
-            self.assertTrue(
-                all(x['id'] < y['id'] for x, y in zip(rows, rows[1:])))
+        rows = ModelStorage.search_read([])
+        self.assertTrue(
+            all(x['id'] < y['id'] for x, y in zip(rows, rows[1:])))
 
-            rows = ModelStorage.search_read([], order=[('name', 'ASC')])
-            self.assertTrue(
-                all(x['name'] <= y['name'] for x, y in zip(rows, rows[1:])))
+        rows = ModelStorage.search_read([], order=[('name', 'ASC')])
+        self.assertTrue(
+            all(x['name'] <= y['name'] for x, y in zip(rows, rows[1:])))
 
-            rows = ModelStorage.search_read([], order=[('name', 'DESC')])
-            self.assertTrue(
-                all(x['name'] >= y['name'] for x, y in zip(rows, rows[1:])))
+        rows = ModelStorage.search_read([], order=[('name', 'DESC')])
+        self.assertTrue(
+            all(x['name'] >= y['name'] for x, y in zip(rows, rows[1:])))
 
 
 def suite():
diff --git a/trytond/tests/test_modelview.py b/trytond/tests/test_modelview.py
index 300978e..cd98369 100644
--- a/trytond/tests/test_modelview.py
+++ b/trytond/tests/test_modelview.py
@@ -3,74 +3,74 @@
 
 import unittest
 
-from trytond.tests.test_tryton import DB_NAME, USER, CONTEXT, install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.pool import Pool
-from trytond.transaction import Transaction
 
 
 class ModelView(unittest.TestCase):
     "Test ModelView"
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
+    @with_transaction()
     def test_changed_values(self):
         "Test ModelView._changed_values"
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            pool = Pool()
-            Model = pool.get('test.modelview.changed_values')
-            Target = pool.get('test.modelview.changed_values.target')
-
-            record = Model()
-
-            self.assertEqual(record._changed_values, {})
-
-            record.name = 'foo'
-            record.target = Target(1)
-            record.ref_target = Target(2)
-            record.targets = [Target(name='bar')]
-            self.assertEqual(record._changed_values, {
-                    'name': 'foo',
-                    'target': 1,
-                    'ref_target': 'test.modelview.changed_values.target,2',
-                    'targets': {
-                        'add': [
-                            (0, {'name': 'bar'}),
-                            ],
-                        },
-                    })
-
-            record = Model(name='test', target=1, targets=[
-                    {'id': 1, 'name': 'foo'},
-                    {'id': 2},
-                    ], m2m_targets=[5, 6, 7])
-
-            self.assertEqual(record._changed_values, {})
-
-            target = record.targets[0]
-            target.name = 'bar'
-            record.targets = [target]
-            record.m2m_targets = [Target(9), Target(10)]
-            self.assertEqual(record._changed_values, {
-                    'targets': {
-                        'update': [{'id': 1, 'name': 'bar'}],
-                        'remove': [2],
-                        },
-                    'm2m_targets': [9, 10],
-                    })
-
-            # change only one2many record
-            record = Model(targets=[{'id': 1, 'name': 'foo'}])
-            self.assertEqual(record._changed_values, {})
-
-            target, = record.targets
-            target.name = 'bar'
-            record.targets = record.targets
-            self.assertEqual(record._changed_values, {
-                    'targets': {
-                        'update': [{'id': 1, 'name': 'bar'}],
-                        },
-                    })
+        pool = Pool()
+        Model = pool.get('test.modelview.changed_values')
+        Target = pool.get('test.modelview.changed_values.target')
+
+        record = Model()
+
+        self.assertEqual(record._changed_values, {})
+
+        record.name = 'foo'
+        record.target = Target(1)
+        record.ref_target = Target(2)
+        record.targets = [Target(name='bar')]
+        self.assertEqual(record._changed_values, {
+                'name': 'foo',
+                'target': 1,
+                'ref_target': 'test.modelview.changed_values.target,2',
+                'targets': {
+                    'add': [
+                        (0, {'name': 'bar'}),
+                        ],
+                    },
+                })
+
+        record = Model(name='test', target=1, targets=[
+                {'id': 1, 'name': 'foo'},
+                {'id': 2},
+                ], m2m_targets=[5, 6, 7])
+
+        self.assertEqual(record._changed_values, {})
+
+        target = record.targets[0]
+        target.name = 'bar'
+        record.targets = [target]
+        record.m2m_targets = [Target(9), Target(10)]
+        self.assertEqual(record._changed_values, {
+                'targets': {
+                    'update': [{'id': 1, 'name': 'bar'}],
+                    'remove': [2],
+                    },
+                'm2m_targets': [9, 10],
+                })
+
+        # change only one2many record
+        record = Model(targets=[{'id': 1, 'name': 'foo'}])
+        self.assertEqual(record._changed_values, {})
+
+        target, = record.targets
+        target.name = 'bar'
+        record.targets = record.targets
+        self.assertEqual(record._changed_values, {
+                'targets': {
+                    'update': [{'id': 1, 'name': 'bar'}],
+                    },
+                })
 
 
 def suite():
diff --git a/trytond/tests/test_mptt.py b/trytond/tests/test_mptt.py
index f4a73e6..5c92af0 100644
--- a/trytond/tests/test_mptt.py
+++ b/trytond/tests/test_mptt.py
@@ -4,21 +4,24 @@
 import sys
 import unittest
 from mock import patch
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 
 
 class MPTTTestCase(unittest.TestCase):
     'Test Modified Preorder Tree Traversal'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.mptt = POOL.get('test.mptt')
 
-    def CheckTree(self, parent_id=None, left=-1, right=sys.maxint):
+    def check_tree(self, parent_id=None, left=-1, right=sys.maxint):
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
+
         with Transaction().set_context(active_test=False):
-            childs = self.mptt.search([
+            childs = Mptt.search([
                     ('parent', '=', parent_id),
                     ], order=[('left', 'ASC')])
         for child in childs:
@@ -31,7 +34,7 @@ class MPTTTestCase(unittest.TestCase):
             assert child.right < right, \
                 '%s: right %d >= parent right %d' % \
                 (child, child.right, right)
-            self.CheckTree(child.id, left=child.left,
+            self.check_tree(child.id, left=child.left,
                 right=child.right)
         next_left = -1
         for child in childs:
@@ -47,8 +50,11 @@ class MPTTTestCase(unittest.TestCase):
                 % (child, child.right, previous_right)
             previous_right = child.left
 
-    def ReParent(self, parent=None):
-        records = self.mptt.search([
+    def reparent(self, parent=None):
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
+
+        records = Mptt.search([
                 ('parent', '=', parent),
                 ])
         if not records:
@@ -61,135 +67,139 @@ class MPTTTestCase(unittest.TestCase):
                     record.parent = parent
                     record.save()
         for record in records:
-            self.ReParent(record)
-
-    def test0010create(self):
+            self.reparent(record)
+
+    def create(self):
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
+
+        new_records = [None, None, None]
+        for j in range(3):
+            parent_records = new_records
+            new_records = []
+            k = 0
+            to_create = []
+            for parent_record in parent_records:
+                to_create.extend([{
+                            'name': 'Test %d %d %d' % (j, k, i),
+                            'parent': (parent_record.id
+                                if parent_record else None),
+                            } for i in range(3)])
+                k += 1
+            new_records = Mptt.create(to_create)
+
+    @with_transaction()
+    def test_create(self):
         'Test create tree'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            new_records = [None, None, None]
-            for j in range(3):
-                parent_records = new_records
-                new_records = []
-                k = 0
-                for parent_record in parent_records:
-                    new_records += self.mptt.create([{
-                                'name': 'Test %d %d %d' % (j, k, i),
-                                'parent': (parent_record.id
-                                    if parent_record else None),
-                                } for i in range(3)])
-                    k += 1
-            self.CheckTree()
-
-            transaction.cursor.commit()
-
-    def test0030reparent(self):
+        self.create()
+        self.check_tree()
+
+    @with_transaction()
+    def test_reparent(self):
         'Test re-parent'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            self.ReParent()
-            transaction.cursor.rollback()
+        self.create()
+        self.reparent()
 
-    def test0040active(self):
+    @with_transaction()
+    def test_active(self):
         'Test active'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            for record in records:
-                if record.id % 2:
-                    record.active = False
-                    record.save()
-            self.CheckTree()
-            self.ReParent()
-            self.CheckTree()
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
 
-            transaction.cursor.rollback()
+        self.create()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            self.mptt.write(records[::2], {
-                    'active': False
-                    })
-            self.CheckTree()
-
-            transaction.cursor.rollback()
-
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            self.mptt.write(records[:len(records) // 2], {
-                    'active': False
-                    })
-            self.CheckTree()
+        records = Mptt.search([])
+        for record in records:
+            if record.id % 2:
+                record.active = False
+                record.save()
+        self.check_tree()
+        self.reparent()
+        self.check_tree()
+
+        records = Mptt.search([])
+        Mptt.write(records, {
+                'active': True,
+                })
+        Mptt.write(records[::2], {
+                'active': False
+                })
+        self.check_tree()
+
+        records = Mptt.search([])
+        Mptt.write(records, {
+                'active': True,
+                })
+        Mptt.write(records[:len(records) // 2], {
+                'active': False
+                })
+        self.check_tree()
+
+        records = Mptt.search([])
+        Mptt.write(records, {
+                'active': False
+                })
+        self.reparent()
+        self.check_tree()
+
+    @with_transaction()
+    def test_delete(self):
+        'Test delete'
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
 
-            transaction.cursor.rollback()
+        self.create()
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            self.mptt.write(records, {
-                    'active': False
-                    })
-            self.ReParent()
-            self.CheckTree()
+        records = Mptt.search([])
+        for record in records:
+            if record.id % 2:
+                Mptt.delete([record])
+        self.check_tree()
 
-            transaction.cursor.rollback()
+        records = Mptt.search([])
+        Mptt.delete(records[:len(records) // 2])
+        self.check_tree()
 
-    def test0050delete(self):
-        'Test delete'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            for record in records:
-                if record.id % 2:
-                    self.mptt.delete([record])
-            self.CheckTree()
+        records = Mptt.search([])
+        Mptt.delete(records)
+        self.check_tree()
 
-            transaction.cursor.rollback()
+    @with_transaction()
+    def test_update_only_if_parent_is_modified(self):
+        'The left and right fields must only be updated if parent is modified'
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            self.mptt.delete(records[:len(records) // 2])
-            self.CheckTree()
+        self.create()
 
-            transaction.cursor.rollback()
+        records = Mptt.search([
+                ('parent', '=', None),
+                ])
+        with patch.object(Mptt, '_update_tree') as update, \
+                patch.object(Mptt, '_rebuild_tree') as rebuild:
+            Mptt.write(records, {'name': 'Parent Records'})
+            self.assertFalse(update.called)
+            self.assertFalse(rebuild.called)
+
+            first_parent, second_parent = records[:2]
+            Mptt.write(list(first_parent.childs), {
+                    'parent': second_parent.id,
+                    })
 
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            records = self.mptt.search([])
-            self.mptt.delete(records)
-            self.CheckTree()
+            self.assertTrue(update.called or rebuild.called)
 
-            transaction.cursor.rollback()
+    @with_transaction()
+    def test_nested_create(self):
+        pool = Pool()
+        Mptt = pool.get('test.mptt')
 
-    def test0060_update_only_if_parent_is_modified(self):
-        'The left and right fields must only be updated if parent is modified'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            records = self.mptt.search([
-                    ('parent', '=', None),
-                    ])
-            with patch.object(self.mptt, '_update_tree') as mock:
-                self.mptt.write(records, {'name': 'Parent Records'})
-                self.assertFalse(mock.called)
-
-                first_parent, second_parent = records[:2]
-                self.mptt.write(list(first_parent.childs), {
-                        'parent': second_parent.id,
-                        })
-
-                self.assertTrue(mock.called)
-
-    def test0070_nested_create(self):
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            record, = self.mptt.create([{
-                        'name': 'Test nested create 1',
-                        'childs': [('create', [{
-                                        'name': 'Test nested create 1 1',
-                                        }])],
-                        }])
-            self.CheckTree()
+        record, = Mptt.create([{
+                    'name': 'Test nested create 1',
+                    'childs': [('create', [{
+                                    'name': 'Test nested create 1 1',
+                                    }])],
+                    }])
+        self.check_tree()
 
 
 def suite():
diff --git a/trytond/tests/test_protocols.py b/trytond/tests/test_protocols.py
index 28ae666..70df424 100644
--- a/trytond/tests/test_protocols.py
+++ b/trytond/tests/test_protocols.py
@@ -7,7 +7,7 @@ import datetime
 from decimal import Decimal
 
 from trytond.protocols.jsonrpc import JSONEncoder, JSONDecoder
-from trytond.protocols.xmlrpc import xmlrpclib
+from trytond.protocols.xmlrpc import client
 
 
 class JSONTestCase(unittest.TestCase):
@@ -44,8 +44,8 @@ class XMLTestCase(unittest.TestCase):
     'Test XML'
 
     def dumps_loads(self, value):
-        s = xmlrpclib.dumps((value,))
-        result, _ = xmlrpclib.loads(s)
+        s = client.dumps((value,))
+        result, _ = client.loads(s)
         result, = result
         self.assertEqual(value, result)
 
diff --git a/trytond/tests/test_pyson.py b/trytond/tests/test_pyson.py
index 99cfe37..3426125 100644
--- a/trytond/tests/test_pyson.py
+++ b/trytond/tests/test_pyson.py
@@ -10,7 +10,7 @@ from trytond import pyson
 class PYSONTestCase(unittest.TestCase):
     'Test PySON'
 
-    def test0010Eval(self):
+    def test_Eval(self):
         'Test pyson.Eval'
         self.assertEqual(pyson.Eval('test').pyson(), {
             '__class__': 'Eval',
@@ -39,7 +39,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertIsInstance(pyson.Eval('test', False) | False, pyson.Or)
         self.assertIsInstance(False | pyson.Eval('test', False), pyson.Or)
 
-    def test0020Not(self):
+    def test_Not(self):
         'Test pyson.Not'
         self.assertEqual(pyson.Not(True).pyson(), {
             '__class__': 'Not',
@@ -58,7 +58,7 @@ class PYSONTestCase(unittest.TestCase):
 
         self.assertEqual(repr(pyson.Not(True)), 'Not(True)')
 
-    def test0030Bool(self):
+    def test_Bool(self):
         'Test pyson.Bool'
         self.assertEqual(pyson.Bool('test').pyson(), {
             '__class__': 'Bool',
@@ -99,7 +99,7 @@ class PYSONTestCase(unittest.TestCase):
 
         self.assertEqual(repr(pyson.Bool('test')), "Bool('test')")
 
-    def test0040And(self):
+    def test_And(self):
         'Test pyson.And'
         self.assertEqual(pyson.And(True, False).pyson(), {
             '__class__': 'And',
@@ -144,7 +144,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.And(False, True, True)),
             'And(False, True, True)')
 
-    def test0050Or(self):
+    def test_Or(self):
         'Test pyson.Or'
         self.assertEqual(pyson.Or(True, False).pyson(), {
             '__class__': 'Or',
@@ -189,7 +189,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.Or(False, True, True)),
             'Or(False, True, True)')
 
-    def test0060Equal(self):
+    def test_Equal(self):
         'Test pyson.Equal'
         self.assertEqual(pyson.Equal('test', 'test').pyson(), {
             '__class__': 'Equal',
@@ -210,7 +210,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.Equal('foo', 'bar')),
             "Equal('foo', 'bar')")
 
-    def test0070Greater(self):
+    def test_Greater(self):
         'Test pyson.Greater'
         self.assertEqual(pyson.Greater(1, 0).pyson(), {
             '__class__': 'Greater',
@@ -245,7 +245,7 @@ class PYSONTestCase(unittest.TestCase):
 
         self.assertEqual(repr(pyson.Greater(1, 0)), 'Greater(1, 0, False)')
 
-    def test0080Less(self):
+    def test_Less(self):
         'Test pyson.Less'
         self.assertEqual(pyson.Less(0, 1).pyson(), {
             '__class__': 'Less',
@@ -280,7 +280,7 @@ class PYSONTestCase(unittest.TestCase):
 
         self.assertEqual(repr(pyson.Less(0, 1)), 'Less(0, 1, False)')
 
-    def test0090If(self):
+    def test_If(self):
         'Test pyson.If'
         self.assertEqual(pyson.If(True, 'foo', 'bar').pyson(), {
             '__class__': 'If',
@@ -305,7 +305,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.If(True, 'foo', 'bar')),
             "If(True, 'foo', 'bar')")
 
-    def test0100Get(self):
+    def test_Get(self):
         'Test pyson.Get'
         self.assertEqual(pyson.Get({'foo': 'bar'}, 'foo', 'default').pyson(), {
             '__class__': 'Get',
@@ -336,7 +336,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.Get({'foo': 'bar'}, 'foo', 'default')),
             "Get({'foo': 'bar'}, 'foo', 'default')")
 
-    def test0110In(self):
+    def test_In(self):
         'Test pyson.In'
         self.assertEqual(pyson.In('foo', {'foo': 'bar'}).pyson(), {
             '__class__': 'In',
@@ -382,7 +382,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.In('foo', ['foo', 'bar'])),
             "In('foo', ['foo', 'bar'])")
 
-    def test0120Date(self):
+    def test_Date(self):
         'Test pyson.Date'
         self.assertEqual(pyson.Date(2010, 1, 12, -1, 12, -7).pyson(), {
             '__class__': 'Date',
@@ -437,7 +437,7 @@ class PYSONTestCase(unittest.TestCase):
         self.assertEqual(repr(pyson.Date(2010, 1, 12, -1, 12, -7)),
             'Date(2010, 1, 12, -1, 12, -7)')
 
-    def test0130DateTime(self):
+    def test_DateTime(self):
         'Test pyson.DateTime'
         self.assertEqual(pyson.DateTime(2010, 1, 12, 10, 30, 20, 0,
             -1, 12, -7, 2, 15, 30, 1).pyson(), {
@@ -539,7 +539,7 @@ class PYSONTestCase(unittest.TestCase):
                     -1, 12, -7, 2, 15, 30, 1)),
             'DateTime(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1)')
 
-    def test0140Len(self):
+    def test_Len(self):
         'Test pyson.Len'
         self.assertEqual(pyson.Len([1, 2, 3]).pyson(), {
                 '__class__': 'Len',
@@ -561,7 +561,7 @@ class PYSONTestCase(unittest.TestCase):
 
         self.assertEqual(repr(pyson.Len([1, 2, 3])), 'Len([1, 2, 3])')
 
-    def test0900Composite(self):
+    def test_Composite(self):
         'Test Composite'
         expr = pyson.If(pyson.Not(
                 pyson.In('company', pyson.Eval('context', {}))), '=', '!=')
diff --git a/trytond/tests/test_sendmail.py b/trytond/tests/test_sendmail.py
new file mode 100644
index 0000000..86b954c
--- /dev/null
+++ b/trytond/tests/test_sendmail.py
@@ -0,0 +1,106 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import unittest
+import smtplib
+from email.message import Message
+from mock import Mock, patch, call
+
+from trytond.sendmail import (
+    sendmail_transactional, sendmail, SMTPDataManager, get_smtp_server)
+from trytond.transaction import Transaction
+from .test_tryton import with_transaction, install_module
+
+
+class SendmailTestCase(unittest.TestCase):
+    'Test sendmail'
+
+    @classmethod
+    def setUpClass(cls):
+        install_module('tests')
+
+    @with_transaction()
+    def test_sendmail_transactional(self):
+        'Test sendmail_transactional'
+        message = Mock()
+        datamanager = Mock()
+        sendmail_transactional(
+            'tryton at example.com', 'foo at example.com', message,
+            datamanager=datamanager)
+
+        datamanager.put.assert_called_once_with(
+            'tryton at example.com', 'foo at example.com', message)
+
+    def test_sendmail(self):
+        'Test sendmail'
+        message = Mock()
+        server = Mock()
+        sendmail(
+            'tryton at example.com', 'foo at example.com', message, server=server)
+        server.sendmail.assert_called_with(
+            'tryton at example.com', 'foo at example.com', message.as_string())
+        server.quit.assert_not_called()
+
+    def test_get_smtp_server(self):
+        'Test get_smtp_server'
+        with patch.object(smtplib, 'SMTP') as SMTP:
+            SMTP.return_value = server = Mock()
+            self.assertEqual(get_smtp_server('smtp://localhost:25'), server)
+            SMTP.assert_called_once_with('localhost', 25)
+
+        with patch.object(smtplib, 'SMTP') as SMTP:
+            SMTP.return_value = server = Mock()
+            self.assertEqual(
+                get_smtp_server('smtp://foo:bar@localhost:25'), server)
+            SMTP.assert_called_once_with('localhost', 25)
+            server.login.assert_called_once_with('foo', 'bar')
+
+        with patch.object(smtplib, 'SMTP_SSL') as SMTP:
+            SMTP.return_value = server = Mock()
+            self.assertEqual(
+                get_smtp_server('smtps://localhost:25'), server)
+            SMTP.assert_called_once_with('localhost', 25)
+
+        with patch.object(smtplib, 'SMTP') as SMTP:
+            SMTP.return_value = server = Mock()
+            self.assertEqual(
+                get_smtp_server('smtp+tls://localhost:25'), server)
+            SMTP.assert_called_once_with('localhost', 25)
+            server.starttls.assert_called_once_with()
+
+    @patch('trytond.sendmail.get_smtp_server')
+    @with_transaction()
+    def test_SMTPDataManager(self, get_smtp_server):
+        'Test SMTPDataManager'
+        transaction = Transaction()
+        get_smtp_server.return_value = server = Mock()
+
+        datamanager = transaction.join(SMTPDataManager())
+
+        # multiple join must return the same
+        self.assertEqual(transaction.join(SMTPDataManager()), datamanager)
+
+        msg1 = Mock(Message)
+        msg2 = Mock(Message)
+        datamanager.put('foo at example.com', 'bar at example.com', msg1)
+        datamanager.put('bar at example.com', 'foo at example.com', msg2)
+
+        transaction.commit()
+
+        server.sendmail.assert_has_calls([
+                call('foo at example.com', 'bar at example.com', msg1.as_string()),
+                call('bar at example.com', 'foo at example.com', msg2.as_string()),
+                ])
+        server.quit.assert_called_once_with()
+        self.assertFalse(datamanager.queue)
+
+        server.reset_mock()
+
+        datamanager.put('foo at example.com', 'bar at example.com', Mock(Message))
+        transaction.rollback()
+
+        server.sendmail.assert_not_called()
+        self.assertFalse(datamanager.queue)
+
+
+def suite():
+    return unittest.TestLoader().loadTestsFromTestCase(SendmailTestCase)
diff --git a/trytond/tests/test_sequence.py b/trytond/tests/test_sequence.py
index e4aa58f..6a3e0f1 100644
--- a/trytond/tests/test_sequence.py
+++ b/trytond/tests/test_sequence.py
@@ -3,112 +3,122 @@
 # this repository contains the full copyright notices and license terms.
 import unittest
 import datetime
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.exceptions import UserError
 
 
 class SequenceTestCase(unittest.TestCase):
     'Test Sequence'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.sequence = POOL.get('ir.sequence')
 
-    def test0010incremental(self):
+    @with_transaction()
+    def test_incremental(self):
         'Test incremental'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            sequence, = self.sequence.create([{
-                        'name': 'Test incremental',
-                        'code': 'test',
-                        'prefix': '',
-                        'suffix': '',
-                        'type': 'incremental',
-                        }])
-            self.assertEqual(self.sequence.get_id(sequence), '1')
-
-            self.sequence.write([sequence], {
-                    'number_increment': 10,
-                    })
-            self.assertEqual(self.sequence.get_id(sequence), '2')
-            self.assertEqual(self.sequence.get_id(sequence), '12')
-
-            self.sequence.write([sequence], {
-                    'padding': 3,
-                    })
-            self.assertEqual(self.sequence.get_id(sequence), '022')
-
-            transaction.cursor.rollback()
-
-    def test0020decimal_timestamp(self):
+        pool = Pool()
+        Sequence = pool.get('ir.sequence')
+
+        sequence, = Sequence.create([{
+                    'name': 'Test incremental',
+                    'code': 'test',
+                    'prefix': '',
+                    'suffix': '',
+                    'type': 'incremental',
+                    }])
+        self.assertEqual(sequence.number_next, 1)
+        self.assertEqual(Sequence.get_id(sequence), '1')
+
+        Sequence.write([sequence], {
+                'number_increment': 10,
+                })
+        self.assertEqual(sequence.number_next, 2)
+        self.assertEqual(Sequence.get_id(sequence), '2')
+        self.assertEqual(Sequence.get_id(sequence), '12')
+
+        Sequence.write([sequence], {
+                'padding': 3,
+                })
+        self.assertEqual(sequence.number_next, 22)
+        self.assertEqual(Sequence.get_id(sequence), '022')
+
+    @with_transaction()
+    def test_decimal_timestamp(self):
         'Test Decimal Timestamp'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            sequence, = self.sequence.create([{
-                        'name': 'Test decimal timestamp',
-                        'code': 'test',
-                        'prefix': '',
-                        'suffix': '',
-                        'type': 'decimal timestamp',
-                        }])
-            timestamp = self.sequence.get_id(sequence)
-            self.assertEqual(timestamp, str(sequence.last_timestamp))
-
-            self.assertNotEqual(self.sequence.get_id(sequence), timestamp)
-
-            next_timestamp = self.sequence._timestamp(sequence)
-            self.assertRaises(UserError, self.sequence.write, [sequence], {
-                    'last_timestamp': next_timestamp + 100,
-                    })
-
-            transaction.cursor.rollback()
-
-    def test0030hexadecimal_timestamp(self):
+        pool = Pool()
+        Sequence = pool.get('ir.sequence')
+
+        sequence, = Sequence.create([{
+                    'name': 'Test decimal timestamp',
+                    'code': 'test',
+                    'prefix': '',
+                    'suffix': '',
+                    'type': 'decimal timestamp',
+                    }])
+        timestamp = Sequence.get_id(sequence)
+        self.assertEqual(timestamp, str(sequence.last_timestamp))
+
+        self.assertEqual(sequence.number_next, None)
+
+        self.assertNotEqual(Sequence.get_id(sequence), timestamp)
+
+        next_timestamp = Sequence._timestamp(sequence)
+        self.assertRaises(UserError, Sequence.write, [sequence], {
+                'last_timestamp': next_timestamp + 100,
+                })
+
+    @with_transaction()
+    def test_hexadecimal_timestamp(self):
         'Test Hexadecimal Timestamp'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            sequence, = self.sequence.create([{
-                        'name': 'Test hexadecimal timestamp',
-                        'code': 'test',
-                        'prefix': '',
-                        'suffix': '',
-                        'type': 'hexadecimal timestamp',
-                        }])
-            timestamp = self.sequence.get_id(sequence)
-            self.assertEqual(timestamp,
-                hex(int(sequence.last_timestamp))[2:].upper())
-
-            self.assertNotEqual(self.sequence.get_id(sequence), timestamp)
-
-            next_timestamp = self.sequence._timestamp(sequence)
-            self.assertRaises(UserError, self.sequence.write, [sequence], {
-                    'last_timestamp': next_timestamp + 100,
-                    })
-
-            transaction.cursor.rollback()
-
-    def test0040prefix_suffix(self):
+        pool = Pool()
+        Sequence = pool.get('ir.sequence')
+
+        sequence, = Sequence.create([{
+                    'name': 'Test hexadecimal timestamp',
+                    'code': 'test',
+                    'prefix': '',
+                    'suffix': '',
+                    'type': 'hexadecimal timestamp',
+                    }])
+        timestamp = Sequence.get_id(sequence)
+        self.assertEqual(timestamp,
+            hex(int(sequence.last_timestamp))[2:].upper())
+
+        self.assertEqual(sequence.number_next, None)
+
+        self.assertNotEqual(Sequence.get_id(sequence), timestamp)
+
+        next_timestamp = Sequence._timestamp(sequence)
+        self.assertRaises(UserError, Sequence.write, [sequence], {
+                'last_timestamp': next_timestamp + 100,
+                })
+
+    @with_transaction()
+    def test_prefix_suffix(self):
         'Test prefix/suffix'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            sequence, = self.sequence.create([{
-                        'name': 'Test incremental',
-                        'code': 'test',
-                        'prefix': 'prefix/',
-                        'suffix': '/suffix',
-                        'type': 'incremental',
-                        }])
-            self.assertEqual(self.sequence.get_id(sequence),
-                'prefix/1/suffix')
-
-            self.sequence.write([sequence], {
-                    'prefix': '${year}-${month}-${day}/',
-                    'suffix': '/${day}.${month}.${year}',
-                    })
-            with Transaction().set_context(date=datetime.date(2010, 8, 15)):
-                self.assertEqual(self.sequence.get_id(sequence),
-                    '2010-08-15/2/15.08.2010')
+        pool = Pool()
+        Sequence = pool.get('ir.sequence')
+
+        sequence, = Sequence.create([{
+                    'name': 'Test incremental',
+                    'code': 'test',
+                    'prefix': 'prefix/',
+                    'suffix': '/suffix',
+                    'type': 'incremental',
+                    }])
+        self.assertEqual(Sequence.get_id(sequence),
+            'prefix/1/suffix')
+
+        Sequence.write([sequence], {
+                'prefix': '${year}-${month}-${day}/',
+                'suffix': '/${day}.${month}.${year}',
+                })
+        with Transaction().set_context(date=datetime.date(2010, 8, 15)):
+            self.assertEqual(Sequence.get_id(sequence),
+                '2010-08-15/2/15.08.2010')
 
 
 def suite():
diff --git a/trytond/tests/test_tools.py b/trytond/tests/test_tools.py
index 28d77e8..39ea282 100644
--- a/trytond/tests/test_tools.py
+++ b/trytond/tests/test_tools.py
@@ -16,41 +16,41 @@ class ToolsTestCase(unittest.TestCase):
     'Test tools'
     table = sql.Table('test')
 
-    def test0000reduce_ids_empty(self):
+    def test_reduce_ids_empty(self):
         'Test reduce_ids empty list'
         self.assertEqual(reduce_ids(self.table.id, []), sql.Literal(False))
 
-    def test0010reduce_ids_continue(self):
+    def test_reduce_ids_continue(self):
         'Test reduce_ids continue list'
         self.assertEqual(reduce_ids(self.table.id, range(10)),
             sql.operators.Or(((self.table.id >= 0) & (self.table.id <= 9),)))
 
-    def test0020reduce_ids_one_hole(self):
+    def test_reduce_ids_one_hole(self):
         'Test reduce_ids continue list with one hole'
         self.assertEqual(reduce_ids(self.table.id, range(10) + range(20, 30)),
             ((self.table.id >= 0) & (self.table.id <= 9))
             | ((self.table.id >= 20) & (self.table.id <= 29)))
 
-    def test0030reduce_ids_short_continue(self):
+    def test_reduce_ids_short_continue(self):
         'Test reduce_ids short continue list'
         self.assertEqual(reduce_ids(self.table.id, range(4)),
             sql.operators.Or((self.table.id.in_(range(4)),)))
 
-    def test0040reduce_ids_complex(self):
+    def test_reduce_ids_complex(self):
         'Test reduce_ids complex list'
         self.assertEqual(reduce_ids(self.table.id,
                 range(10) + range(25, 30) + range(15, 20)),
             (((self.table.id >= 0) & (self.table.id <= 14))
                 | (self.table.id.in_(range(25, 30)))))
 
-    def test0050reduce_ids_complex_small_continue(self):
+    def test_reduce_ids_complex_small_continue(self):
         'Test reduce_ids complex list with small continue'
         self.assertEqual(reduce_ids(self.table.id,
                 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 18, 19, 21]),
             (((self.table.id >= 1) & (self.table.id <= 12))
                 | (self.table.id.in_([15, 18, 19, 21]))))
 
-    def test0055reduce_ids_float(self):
+    def test_reduce_ids_float(self):
         'Test reduce_ids with integer as float'
         self.assertEqual(reduce_ids(self.table.id,
                 [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
@@ -59,7 +59,7 @@ class ToolsTestCase(unittest.TestCase):
                 | (self.table.id.in_([15.0, 18.0, 19.0, 21.0]))))
         self.assertRaises(AssertionError, reduce_ids, self.table.id, [1.1])
 
-    def test0070datetime_strftime(self):
+    def test_datetime_strftime(self):
         'Test datetime_strftime'
         self.assert_(datetime_strftime(datetime.date(2005, 3, 2),
             '%Y-%m-%d'), '2005-03-02')
diff --git a/trytond/tests/test_transaction.py b/trytond/tests/test_transaction.py
index 10aef42..6360d47 100644
--- a/trytond/tests/test_transaction.py
+++ b/trytond/tests/test_transaction.py
@@ -1,6 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 import unittest
+from mock import Mock
 from trytond.tests.test_tryton import DB_NAME, USER, CONTEXT, install_module
 from trytond.transaction import Transaction
 
@@ -16,24 +17,14 @@ def empty_transaction(*args, **kwargs):
         return True
 
 
-def manipulate_cursor(*args, **kwargs):
-    '''
-    Just start a transaction in the context manager and close the cursor
-    during the transaction so that the cursor.close in the stop fails
-    '''
-    with Transaction().start(*args, **kwargs) as transaction:
-        transaction.cursor.close()
-        transaction.cursor = None
-        return True
-
-
 class TransactionTestCase(unittest.TestCase):
     'Test the Transaction Context manager'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
-    def test0010nonexistdb(self):
+    def test_nonexistdb(self):
         '''Attempt opening a transaction with a non existant DB
         and ensure that it stops cleanly and allows starting of next
         transaction'''
@@ -42,15 +33,7 @@ class TransactionTestCase(unittest.TestCase):
             context=CONTEXT)
         self.assertTrue(empty_transaction(DB_NAME, USER, context=CONTEXT))
 
-    def test0020cursorclose(self):
-        '''Manipulate the cursor during the transaction so that
-        the close in transaction stop fails.
-        Ensure that this does not affect opening of another transaction'''
-        self.assertRaises(
-            Exception, manipulate_cursor, DB_NAME, USER, context=CONTEXT)
-        self.assertTrue(empty_transaction(DB_NAME, USER, context=CONTEXT))
-
-    def test0030set_user(self):
+    def test_set_user(self):
         'Test set_user'
         with Transaction().start(DB_NAME, USER, context=CONTEXT) \
                 as transaction:
@@ -83,6 +66,61 @@ class TransactionTestCase(unittest.TestCase):
             with Transaction().set_user(2):
                 self.assertEqual(transaction.user, 2)
 
+    def test_stacked_transactions(self):
+        'Test that transactions are stacked / unstacked correctly'
+        with Transaction().start(DB_NAME, USER, context=CONTEXT) \
+                as transaction:
+            with transaction.new_transaction() as new_transaction:
+                self.assertIsNot(new_transaction, transaction)
+                self.assertIsNot(Transaction(), transaction)
+                self.assertIs(Transaction(), new_transaction)
+            self.assertIs(Transaction(), transaction)
+
+    def test_two_phase_commit(self):
+        # A successful transaction
+        dm = Mock()
+        with Transaction().start(DB_NAME, USER, context=CONTEXT) \
+                as transaction:
+            transaction.join(dm)
+
+        dm.tpc_begin.assert_called_once_with(transaction)
+        dm.commit.assert_called_once_with(transaction)
+        dm.tpc_vote.assert_called_once_with(transaction)
+        dm.tpc_abort.not_called()
+        dm.tpc_finish.assert_called_once_with(transaction)
+
+        # Failing in the datamanager
+        dm.reset_mock()
+        dm.tpc_vote.side_effect = ValueError('Failing the datamanager')
+        try:
+            with Transaction().start(DB_NAME, USER, context=CONTEXT) \
+                    as transaction:
+                transaction.join(dm)
+        except ValueError:
+            pass
+
+        dm.tpc_begin.assert_called_once_with(transaction)
+        dm.commit.assert_called_once_with(transaction)
+        dm.tpc_vote.assert_called_once_with(transaction)
+        dm.tpc_abort.assert_called_once_with(transaction)
+        dm.tpc_finish.assert_not_called()
+
+        # Failing in tryton
+        dm.reset_mock()
+        try:
+            with Transaction().start(DB_NAME, USER, context=CONTEXT) \
+                    as transaction:
+                transaction.join(dm)
+                raise ValueError('Failing in tryton')
+        except ValueError:
+            pass
+
+        dm.tpc_begin.assert_not_called()
+        dm.commit.assert_not_called()
+        dm.tpc_vote.assert_not_called()
+        dm.tpc_abort.assert_called_once_with(transaction)
+        dm.tpc_finish.assert_not_called()
+
 
 def suite():
     return unittest.TestLoader().loadTestsFromTestCase(TransactionTestCase)
diff --git a/trytond/tests/test_trigger.py b/trytond/tests/test_trigger.py
index 4f24741..1d89838 100644
--- a/trytond/tests/test_trigger.py
+++ b/trytond/tests/test_trigger.py
@@ -6,10 +6,10 @@ import time
 import datetime
 from itertools import combinations
 
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.tests.trigger import TRIGGER_LOGS
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 from trytond.exceptions import UserError
 from trytond.pyson import PYSONEncoder, Eval
 
@@ -17,429 +17,446 @@ from trytond.pyson import PYSONEncoder, Eval
 class TriggerTestCase(unittest.TestCase):
     'Test Trigger'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.triggered = POOL.get('test.triggered')
-        self.trigger = POOL.get('ir.trigger')
-        self.trigger_log = POOL.get('ir.trigger.log')
-        self.model = POOL.get('ir.model')
 
-    def test0010constraints(self):
+    @with_transaction()
+    def test_constraints(self):
         'Test constraints'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            model, = self.model.search([
-                    ('model', '=', 'test.triggered'),
-                    ])
-            action_model, = self.model.search([
-                    ('model', '=', 'test.trigger_action'),
-                    ])
-
-            values = {
-                'name': 'Test',
-                'model': model.id,
-                'on_time': True,
-                'condition': 'true',
-                'action_model': action_model.id,
-                'action_function': 'test',
-                }
-            self.assert_(self.trigger.create([values]))
+        pool = Pool()
+        Model = pool.get('ir.model')
+        Trigger = pool.get('ir.trigger')
+        transaction = Transaction()
+
+        model, = Model.search([
+                ('model', '=', 'test.triggered'),
+                ])
+        action_model, = Model.search([
+                ('model', '=', 'test.trigger_action'),
+                ])
+
+        values = {
+            'name': 'Test',
+            'model': model.id,
+            'on_time': True,
+            'condition': 'true',
+            'action_model': action_model.id,
+            'action_function': 'test',
+            }
+        self.assert_(Trigger.create([values]))
+
+        transaction.rollback()
 
         # on_exclusive
         for i in range(1, 4):
             for combination in combinations(
                     ['create', 'write', 'delete'], i):
-                with Transaction().start(DB_NAME, USER, context=CONTEXT):
-                    combination_values = values.copy()
-                    for mode in combination:
-                        combination_values['on_%s' % mode] = True
-                    self.assertRaises(UserError, self.trigger.create,
-                        [combination_values])
-
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            # check_condition
-            condition_values = values.copy()
-            condition_values['condition'] = '='
-            self.assertRaises(UserError, self.trigger.create,
-                [condition_values])
-
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            # Restart the cache on the get_triggers method of ir.trigger
-            self.trigger._get_triggers_cache.clear()
-
-    def test0020on_create(self):
+                combination_values = values.copy()
+                for mode in combination:
+                    combination_values['on_%s' % mode] = True
+                self.assertRaises(UserError, Trigger.create,
+                    [combination_values])
+                transaction.rollback()
+
+        # check_condition
+        condition_values = values.copy()
+        condition_values['condition'] = '='
+        self.assertRaises(UserError, Trigger.create,
+            [condition_values])
+        transaction.rollback()
+
+        # Restart the cache on the get_triggers method of ir.trigger
+        Trigger._get_triggers_cache.clear()
+
+    @with_transaction()
+    def test_on_create(self):
         'Test on_create'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([
-                    ('model', '=', 'test.triggered'),
-                    ])
-            action_model, = self.model.search([
-                    ('model', '=', 'test.trigger_action'),
-                    ])
-
-            trigger, = self.trigger.create([{
-                        'name': 'Test',
-                        'model': model.id,
-                        'on_create': True,
-                        'condition': 'true',
-                        'action_model': action_model.id,
-                        'action_function': 'trigger',
-                        }])
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # Trigger with condition
-            condition = PYSONEncoder().encode(
-                Eval('self', {}).get('name') == 'Bar')
-            self.trigger.write([trigger], {
-                    'condition': condition,
-                    })
-
-            # Matching condition
-            triggered, = self.triggered.create([{
-                        'name': 'Bar',
-                        }])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # Non matching condition
-            triggered, = self.triggered.create([{
-                        'name': 'Foo',
-                        }])
-            self.assertEqual(TRIGGER_LOGS, [])
-
-            # With limit number
-            self.trigger.write([trigger], {
+        pool = Pool()
+        Model = pool.get('ir.model')
+        Trigger = pool.get('ir.trigger')
+        Triggered = pool.get('test.triggered')
+
+        model, = Model.search([
+                ('model', '=', 'test.triggered'),
+                ])
+        action_model, = Model.search([
+                ('model', '=', 'test.trigger_action'),
+                ])
+
+        trigger, = Trigger.create([{
+                    'name': 'Test',
+                    'model': model.id,
+                    'on_create': True,
                     'condition': 'true',
-                    'limit_number': 1,
-                    })
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # With minimum delay
-            self.trigger.write([trigger], {
-                    'limit_number': 0,
-                    'minimum_time_delay': datetime.timedelta(hours=1),
-                    })
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
+                    'action_model': action_model.id,
+                    'action_function': 'trigger',
+                    }])
+
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # Trigger with condition
+        condition = PYSONEncoder().encode(
+            Eval('self', {}).get('name') == 'Bar')
+        Trigger.write([trigger], {
+                'condition': condition,
+                })
+
+        # Matching condition
+        triggered, = Triggered.create([{
+                    'name': 'Bar',
+                    }])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
 
-            # Restart the cache on the get_triggers method of ir.trigger
-            self.trigger._get_triggers_cache.clear()
-            transaction.cursor.rollback()
+        # Non matching condition
+        triggered, = Triggered.create([{
+                    'name': 'Foo',
+                    }])
+        self.assertEqual(TRIGGER_LOGS, [])
 
+        # With limit number
+        Trigger.write([trigger], {
+                'condition': 'true',
+                'limit_number': 1,
+                })
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # With minimum delay
+        Trigger.write([trigger], {
+                'limit_number': 0,
+                'minimum_time_delay': datetime.timedelta(hours=1),
+                })
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # Restart the cache on the get_triggers method of ir.trigger
+        Trigger._get_triggers_cache.clear()
+
+    @with_transaction()
     def test0030on_write(self):
         'Test on_write'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([
-                    ('model', '=', 'test.triggered'),
-                    ])
-            action_model, = self.model.search([
-                    ('model', '=', 'test.trigger_action'),
-                    ])
-
-            trigger, = self.trigger.create([{
-                        'name': 'Test',
-                        'model': model.id,
-                        'on_write': True,
-                        'condition': 'true',
-                        'action_model': action_model.id,
-                        'action_function': 'trigger',
-                        }])
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-
-            self.triggered.write([triggered], {
-                    'name': 'Foo',
-                    })
-            self.assertEqual(TRIGGER_LOGS, [])
-
-            # Trigger with condition
-            condition = PYSONEncoder().encode(
-                Eval('self', {}).get('name') == 'Bar')
-            self.trigger.write([trigger], {
-                    'condition': condition,
-                    })
-
-            # Matching condition
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
-                    })
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # No change in condition
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
-                    })
-            self.assertEqual(TRIGGER_LOGS, [])
-
-            # Different change in condition
-            self.triggered.write([triggered], {
+        pool = Pool()
+        Model = pool.get('ir.model')
+        Trigger = pool.get('ir.trigger')
+        Triggered = pool.get('test.triggered')
+
+        model, = Model.search([
+                ('model', '=', 'test.triggered'),
+                ])
+        action_model, = Model.search([
+                ('model', '=', 'test.trigger_action'),
+                ])
+
+        trigger, = Trigger.create([{
+                    'name': 'Test',
+                    'model': model.id,
+                    'on_write': True,
+                    'condition': 'true',
+                    'action_model': action_model.id,
+                    'action_function': 'trigger',
+                    }])
+
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+
+        Triggered.write([triggered], {
+                'name': 'Foo',
+                })
+        self.assertEqual(TRIGGER_LOGS, [])
+
+        # Trigger with condition
+        condition = PYSONEncoder().encode(
+            Eval('self', {}).get('name') == 'Bar')
+        Trigger.write([trigger], {
+                'condition': condition,
+                })
+
+        # Matching condition
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # No change in condition
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        self.assertEqual(TRIGGER_LOGS, [])
+
+        # Different change in condition
+        Triggered.write([triggered], {
+                'name': 'Foo',
+                })
+        self.assertEqual(TRIGGER_LOGS, [])
+
+        # With limit number
+        condition = PYSONEncoder().encode(
+            Eval('self', {}).get('name') == 'Bar')
+        Trigger.write([trigger], {
+                'condition': condition,
+                'limit_number': 1,
+                })
+        triggered, = Triggered.create([{
                     'name': 'Foo',
-                    })
-            self.assertEqual(TRIGGER_LOGS, [])
-
-            # With limit number
-            condition = PYSONEncoder().encode(
-                Eval('self', {}).get('name') == 'Bar')
-            self.trigger.write([trigger], {
-                    'condition': condition,
-                    'limit_number': 1,
-                    })
-            triggered, = self.triggered.create([{
-                        'name': 'Foo',
-                        }])
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
-                    })
-            self.triggered.write([triggered], {
+                    }])
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        Triggered.write([triggered], {
+                'name': 'Foo',
+                })
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # With minimum delay
+        Trigger.write([trigger], {
+                'limit_number': 0,
+                'minimum_time_delay': datetime.timedelta.max,
+                })
+        triggered, = Triggered.create([{
                     'name': 'Foo',
+                    }])
+        for name in ('Bar', 'Foo', 'Bar'):
+            Triggered.write([triggered], {
+                    'name': name,
                     })
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
-                    })
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
 
-            # With minimum delay
-            self.trigger.write([trigger], {
-                    'limit_number': 0,
-                    'minimum_time_delay': datetime.timedelta.max,
-                    })
-            triggered, = self.triggered.create([{
-                        'name': 'Foo',
-                        }])
-            for name in ('Bar', 'Foo', 'Bar'):
-                self.triggered.write([triggered], {
-                        'name': name,
-                        })
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            self.trigger.write([trigger], {
-                    'minimum_time_delay': datetime.timedelta(seconds=1),
-                    })
-            triggered, = self.triggered.create([{
-                        'name': 'Foo',
-                        }])
-            for name in ('Bar', 'Foo'):
-                self.triggered.write([triggered], {
-                        'name': name,
-                        })
-            time.sleep(1.2)
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
+        Trigger.write([trigger], {
+                'minimum_time_delay': datetime.timedelta(seconds=1),
+                })
+        triggered, = Triggered.create([{
+                    'name': 'Foo',
+                    }])
+        for name in ('Bar', 'Foo'):
+            Triggered.write([triggered], {
+                    'name': name,
                     })
-            self.assertEqual(TRIGGER_LOGS,
-                [([triggered], trigger), ([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            TRIGGER_LOGS.pop()
-
-            # Restart the cache on the get_triggers method of ir.trigger
-            self.trigger._get_triggers_cache.clear()
-            transaction.cursor.rollback()
-
+        time.sleep(1.2)
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        self.assertEqual(TRIGGER_LOGS,
+            [([triggered], trigger), ([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        TRIGGER_LOGS.pop()
+
+        # Restart the cache on the get_triggers method of ir.trigger
+        Trigger._get_triggers_cache.clear()
+
+    @with_transaction()
     def test0040on_delete(self):
         'Test on_delete'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([
-                    ('model', '=', 'test.triggered'),
-                    ])
-            action_model, = self.model.search([
-                    ('model', '=', 'test.trigger_action'),
-                    ])
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-
-            trigger, = self.trigger.create([{
-                        'name': 'Test',
-                        'model': model.id,
-                        'on_delete': True,
-                        'condition': 'true',
-                        'action_model': action_model.id,
-                        'action_function': 'trigger',
-                        }])
-
-            self.triggered.delete([triggered])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
-
-            # Trigger with condition
-            condition = PYSONEncoder().encode(
-                Eval('self', {}).get('name') == 'Bar')
-            self.trigger.write([trigger], {
-                    'condition': condition,
-                    })
-
-            triggered, = self.triggered.create([{
-                        'name': 'Bar',
-                        }])
-
-            # Matching condition
-            self.triggered.delete([triggered])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
-
-            triggered, = self.triggered.create([{
-                        'name': 'Foo',
-                        }])
-
-            # Non matching condition
-            self.triggered.delete([triggered])
-            self.assertEqual(TRIGGER_LOGS, [])
-            Transaction().delete = {}
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-
-            # With limit number
-            self.trigger.write([trigger], {
+        pool = Pool()
+        Model = pool.get('ir.model')
+        Trigger = pool.get('ir.trigger')
+        Triggered = pool.get('test.triggered')
+        TriggerLog = pool.get('ir.trigger.log')
+
+        model, = Model.search([
+                ('model', '=', 'test.triggered'),
+                ])
+        action_model, = Model.search([
+                ('model', '=', 'test.trigger_action'),
+                ])
+
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+
+        trigger, = Trigger.create([{
+                    'name': 'Test',
+                    'model': model.id,
+                    'on_delete': True,
                     'condition': 'true',
-                    'limit_number': 1,
-                    })
-            self.triggered.delete([triggered])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
-            # Delete trigger logs because SQLite reuse the same triggered_id
-            self.trigger_log.delete(self.trigger_log.search([
-                        ('trigger', '=', trigger.id),
-                        ]))
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-
-            # With minimum delay
-            self.trigger.write([trigger], {
-                    'limit_number': 0,
-                    'minimum_time_delay': datetime.timedelta(hours=1),
-                    })
-            self.triggered.delete([triggered])
-            self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
+                    'action_model': action_model.id,
+                    'action_function': 'trigger',
+                    }])
+
+        Triggered.delete([triggered])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
+
+        # Trigger with condition
+        condition = PYSONEncoder().encode(
+            Eval('self', {}).get('name') == 'Bar')
+        Trigger.write([trigger], {
+                'condition': condition,
+                })
+
+        triggered, = Triggered.create([{
+                    'name': 'Bar',
+                    }])
 
-            # Restart the cache on the get_triggers method of ir.trigger
-            self.trigger._get_triggers_cache.clear()
-            transaction.cursor.rollback()
+        # Matching condition
+        Triggered.delete([triggered])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
 
-    def test0050on_time(self):
-        'Test on_time'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            model, = self.model.search([
-                    ('model', '=', 'test.triggered'),
-                    ])
-            action_model, = self.model.search([
-                    ('model', '=', 'test.trigger_action'),
-                    ])
-
-            trigger, = self.trigger.create([{
-                        'name': 'Test',
-                        'model': model.id,
-                        'on_time': True,
-                        'condition': 'true',
-                        'action_model': action_model.id,
-                        'action_function': 'trigger',
-                        }])
-
-            triggered, = self.triggered.create([{
-                        'name': 'Test',
-                        }])
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # Trigger with condition
-            condition = PYSONEncoder().encode(
-                Eval('self', {}).get('name') == 'Bar')
-            self.trigger.write([trigger], {
-                    'condition': condition,
-                    })
+        triggered, = Triggered.create([{
+                    'name': 'Foo',
+                    }])
 
-            # Matching condition
-            self.triggered.write([triggered], {
-                    'name': 'Bar',
-                    })
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
+        # Non matching condition
+        Triggered.delete([triggered])
+        self.assertEqual(TRIGGER_LOGS, [])
+        Transaction().delete = {}
 
-            # Non matching condition
-            self.triggered.write([triggered], {
-                    'name': 'Foo',
-                    })
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [])
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
 
-            # With limit number
-            self.trigger.write([trigger], {
+        # With limit number
+        Trigger.write([trigger], {
+                'condition': 'true',
+                'limit_number': 1,
+                })
+        Triggered.delete([triggered])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
+        # Delete trigger logs because SQLite reuse the same triggered_id
+        TriggerLog.delete(TriggerLog.search([
+                    ('trigger', '=', trigger.id),
+                    ]))
+
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+
+        # With minimum delay
+        Trigger.write([trigger], {
+                'limit_number': 0,
+                'minimum_time_delay': datetime.timedelta(hours=1),
+                })
+        Triggered.delete([triggered])
+        self.assertEqual(TRIGGER_LOGS, [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
+
+        # Restart the cache on the get_triggers method of ir.trigger
+        Trigger._get_triggers_cache.clear()
+
+    @with_transaction()
+    def test_on_time(self):
+        'Test on_time'
+        pool = Pool()
+        Model = pool.get('ir.model')
+        Trigger = pool.get('ir.trigger')
+        Triggered = pool.get('test.triggered')
+        TriggerLog = pool.get('ir.trigger.log')
+
+        model, = Model.search([
+                ('model', '=', 'test.triggered'),
+                ])
+        action_model, = Model.search([
+                ('model', '=', 'test.trigger_action'),
+                ])
+
+        trigger, = Trigger.create([{
+                    'name': 'Test',
+                    'model': model.id,
+                    'on_time': True,
                     'condition': 'true',
-                    'limit_number': 1,
-                    })
-            self.trigger.trigger_time()
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-
-            # Delete trigger logs of limit number test
-            self.trigger_log.delete(self.trigger_log.search([
-                        ('trigger', '=', trigger.id),
-                        ]))
-
-            # With minimum delay
-            self.trigger.write([trigger], {
-                    'limit_number': 0,
-                    'minimum_time_delay': datetime.timedelta.max,
-                    })
-            self.trigger.trigger_time()
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
-
-            # Delete trigger logs of previous minimum delay test
-            self.trigger_log.delete(self.trigger_log.search([
-                        ('trigger', '=', trigger.id),
-                        ]))
-
-            self.trigger.write([trigger], {
-                    'minimum_time_delay': datetime.timedelta(seconds=1),
-                    })
-            self.trigger.trigger_time()
-            time.sleep(1.2)
-            self.trigger.trigger_time()
-            self.assert_(TRIGGER_LOGS == [([triggered], trigger),
-                    ([triggered], trigger)])
-            TRIGGER_LOGS.pop()
-            TRIGGER_LOGS.pop()
-            Transaction().delete = {}
-
-            # Restart the cache on the get_triggers method of ir.trigger
-            self.trigger._get_triggers_cache.clear()
-            transaction.cursor.rollback()
+                    'action_model': action_model.id,
+                    'action_function': 'trigger',
+                    }])
+
+        triggered, = Triggered.create([{
+                    'name': 'Test',
+                    }])
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # Trigger with condition
+        condition = PYSONEncoder().encode(
+            Eval('self', {}).get('name') == 'Bar')
+        Trigger.write([trigger], {
+                'condition': condition,
+                })
+
+        # Matching condition
+        Triggered.write([triggered], {
+                'name': 'Bar',
+                })
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # Non matching condition
+        Triggered.write([triggered], {
+                'name': 'Foo',
+                })
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [])
+
+        # With limit number
+        Trigger.write([trigger], {
+                'condition': 'true',
+                'limit_number': 1,
+                })
+        Trigger.trigger_time()
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+
+        # Delete trigger logs of limit number test
+        TriggerLog.delete(TriggerLog.search([
+                    ('trigger', '=', trigger.id),
+                    ]))
+
+        # With minimum delay
+        Trigger.write([trigger], {
+                'limit_number': 0,
+                'minimum_time_delay': datetime.timedelta.max,
+                })
+        Trigger.trigger_time()
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
+
+        # Delete trigger logs of previous minimum delay test
+        TriggerLog.delete(TriggerLog.search([
+                    ('trigger', '=', trigger.id),
+                    ]))
+
+        Trigger.write([trigger], {
+                'minimum_time_delay': datetime.timedelta(seconds=1),
+                })
+        Trigger.trigger_time()
+        time.sleep(1.2)
+        Trigger.trigger_time()
+        self.assert_(TRIGGER_LOGS == [([triggered], trigger),
+                ([triggered], trigger)])
+        TRIGGER_LOGS.pop()
+        TRIGGER_LOGS.pop()
+        Transaction().delete = {}
+
+        # Restart the cache on the get_triggers method of ir.trigger
+        Trigger._get_triggers_cache.clear()
 
 
 def suite():
diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py
index b92a742..fad1a5b 100644
--- a/trytond/tests/test_tryton.py
+++ b/trytond/tests/test_tryton.py
@@ -5,8 +5,11 @@ import os
 import sys
 import unittest
 import doctest
+import re
 from itertools import chain
 import operator
+from functools import wraps
+
 from lxml import etree
 
 from trytond.pool import Pool, isregisteredby
@@ -17,10 +20,11 @@ from trytond.protocols.dispatcher import create, drop
 from trytond.tools import is_instance_method
 from trytond.transaction import Transaction
 from trytond import security
+from trytond.cache import Cache
 
 __all__ = ['POOL', 'DB_NAME', 'USER', 'USER_PASSWORD', 'CONTEXT',
-    'install_module', 'ModuleTestCase',
-    'doctest_setup', 'doctest_teardown',
+    'install_module', 'ModuleTestCase', 'with_transaction',
+    'doctest_setup', 'doctest_teardown', 'doctest_checker',
     'suite', 'all_suite', 'modules_suite']
 
 Pool.start()
@@ -39,8 +43,7 @@ def install_module(name):
     Install module for the tested database
     '''
     create_db()
-    with Transaction().start(DB_NAME, USER,
-            context=CONTEXT) as transaction:
+    with Transaction().start(DB_NAME, 1) as transaction:
         Module = POOL.get('ir.module')
 
         modules = Module.search([
@@ -57,212 +60,238 @@ def install_module(name):
             return
 
         Module.install(modules)
-        transaction.cursor.commit()
+        transaction.commit()
 
         InstallUpgrade = POOL.get('ir.module.install_upgrade',
             type='wizard')
         instance_id, _, _ = InstallUpgrade.create()
-        transaction.cursor.commit()
+        transaction.commit()
         InstallUpgrade(instance_id).transition_upgrade()
         InstallUpgrade.delete(instance_id)
-        transaction.cursor.commit()
+        transaction.commit()
+
+
+def with_transaction(user=1, context=None):
+    def decorator(func):
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            transaction = Transaction()
+            with transaction.start(DB_NAME, user, context=context):
+                result = func(*args, **kwargs)
+                transaction.rollback()
+                # Drop the cache as the transaction is rollbacked
+                Cache.drop(DB_NAME)
+                return result
+        return wrapper
+    return decorator
 
 
 class ModuleTestCase(unittest.TestCase):
     'Trytond Test Case'
     module = None
 
-    def setUp(self):
-        install_module(self.module)
+    @classmethod
+    def setUpClass(cls):
+        drop_create()
+        install_module(cls.module)
+        super(ModuleTestCase, cls).setUpClass()
 
+    @classmethod
+    def tearDownClass(cls):
+        super(ModuleTestCase, cls).tearDownClass()
+        drop_db()
+
+    @with_transaction()
     def test_rec_name(self):
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for mname, model in Pool().iterobject():
-                if not isregisteredby(model, self.module):
-                    continue
-                # Skip testing default value even if the field doesn't exist
-                # as there is a fallback to id
-                if model._rec_name == 'name':
-                    continue
-                assert model._rec_name in model._fields, (
-                    'Wrong _rec_name "%s" for %s'
-                    % (model._rec_name, mname))
+        for mname, model in Pool().iterobject():
+            if not isregisteredby(model, self.module):
+                continue
+            # Skip testing default value even if the field doesn't exist
+            # as there is a fallback to id
+            if model._rec_name == 'name':
+                continue
+            assert model._rec_name in model._fields, (
+                'Wrong _rec_name "%s" for %s'
+                % (model._rec_name, mname))
 
+    @with_transaction()
     def test_view(self):
         'Test validity of all views of the module'
-        with Transaction().start(DB_NAME, USER,
-                context=CONTEXT) as transaction:
-            View = POOL.get('ir.ui.view')
-            views = View.search([
-                    ('module', '=', self.module),
-                    ('model', '!=', ''),
-                    ])
-            for view in views:
-                if view.inherit and view.inherit.model == view.model:
-                    view_id = view.inherit.id
-                else:
-                    view_id = view.id
-                model = view.model
-                Model = POOL.get(model)
-                res = Model.fields_view_get(view_id)
-                assert res['model'] == model
-                tree = etree.fromstring(res['arch'])
-
-                validator = etree.RelaxNG(etree=View.get_rng(res['type']))
-                validator.assert_(tree)
-
-                tree_root = tree.getroottree().getroot()
-
-                for element in tree_root.iter():
-                    if element.tag in ('field', 'label', 'separator', 'group'):
-                        for attr in ('name', 'icon'):
-                            field = element.get(attr)
-                            if field:
-                                assert field in res['fields'], (
-                                    'Missing field: %s' % field)
-            transaction.cursor.rollback()
-
+        View = POOL.get('ir.ui.view')
+        views = View.search([
+                ('module', '=', self.module),
+                ('model', '!=', ''),
+                ])
+        for view in views:
+            if view.inherit and view.inherit.model == view.model:
+                view_id = view.inherit.id
+            else:
+                view_id = view.id
+            model = view.model
+            Model = POOL.get(model)
+            res = Model.fields_view_get(view_id)
+            assert res['model'] == model
+            tree = etree.fromstring(res['arch'])
+
+            validator = etree.RelaxNG(etree=View.get_rng(res['type']))
+            # Don't use assert_ because 2to3 convert to assertTrue
+            validator.assertValid(tree)
+
+            tree_root = tree.getroottree().getroot()
+
+            for element in tree_root.iter():
+                if element.tag in ('field', 'label', 'separator', 'group'):
+                    for attr in ('name', 'icon'):
+                        field = element.get(attr)
+                        if field:
+                            assert field in res['fields'], (
+                                'Missing field: %s' % field)
+
+    @with_transaction()
     def test_depends(self):
         'Test for missing depends'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for mname, model in Pool().iterobject():
-                if not isregisteredby(model, self.module):
-                    continue
-                for fname, field in model._fields.iteritems():
-                    fields = set()
-                    fields |= get_eval_fields(field.domain)
-                    if hasattr(field, 'digits'):
-                        fields |= get_eval_fields(field.digits)
-                    if hasattr(field, 'add_remove'):
-                        fields |= get_eval_fields(field.add_remove)
-                    fields.discard(fname)
-                    fields.discard('context')
-                    fields.discard('_user')
-                    depends = set(field.depends)
-                    assert fields <= depends, (
-                        'Missing depends %s in "%s"."%s"' % (
-                            list(fields - depends), mname, fname))
-                    assert depends <= set(model._fields), (
-                        'Unknown depends %s in "%s"."%s"' % (
-                            list(depends - set(model._fields)), mname, fname))
-
+        for mname, model in Pool().iterobject():
+            if not isregisteredby(model, self.module):
+                continue
+            for fname, field in model._fields.iteritems():
+                fields = set()
+                fields |= get_eval_fields(field.domain)
+                if hasattr(field, 'digits'):
+                    fields |= get_eval_fields(field.digits)
+                if hasattr(field, 'add_remove'):
+                    fields |= get_eval_fields(field.add_remove)
+                fields.discard(fname)
+                fields.discard('context')
+                fields.discard('_user')
+                depends = set(field.depends)
+                assert fields <= depends, (
+                    'Missing depends %s in "%s"."%s"' % (
+                        list(fields - depends), mname, fname))
+                assert depends <= set(model._fields), (
+                    'Unknown depends %s in "%s"."%s"' % (
+                        list(depends - set(model._fields)), mname, fname))
+
+    @with_transaction()
     def test_field_methods(self):
         'Test field methods'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for mname, model in Pool().iterobject():
-                if not isregisteredby(model, self.module):
-                    continue
-                for attr in dir(model):
-                    for prefixes in [['default_'],
-                            ['on_change_', 'on_change_with_'],
-                            ['order_'], ['domain_'], ['autocomplete_']]:
-                        if attr == 'on_change_with':
-                            continue
-                        # TODO those method should be renamed
-                        if attr == 'default_get':
-                            continue
-                        if mname == 'ir.rule' and attr == 'domain_get':
-                            continue
-
-                        # Skip if it is a field
-                        if attr in model._fields:
-                            continue
-                        fnames = [attr[len(prefix):] for prefix in prefixes
-                            if attr.startswith(prefix)]
-                        if not fnames:
-                            continue
-                        assert any(f in model._fields for f in fnames), (
-                            'Field method "%s"."%s" for unknown field' % (
-                                mname, attr))
+        for mname, model in Pool().iterobject():
+            if not isregisteredby(model, self.module):
+                continue
+            for attr in dir(model):
+                for prefixes in [['default_'],
+                        ['on_change_', 'on_change_with_'],
+                        ['order_'], ['domain_'], ['autocomplete_']]:
+                    if attr == 'on_change_with':
+                        continue
+                    # TODO those method should be renamed
+                    if attr == 'default_get':
+                        continue
+                    if mname == 'ir.rule' and attr == 'domain_get':
+                        continue
+
+                    # Skip if it is a field
+                    if attr in model._fields:
+                        continue
+                    fnames = [attr[len(prefix):] for prefix in prefixes
+                        if attr.startswith(prefix)]
+                    if not fnames:
+                        continue
+                    assert any(f in model._fields for f in fnames), (
+                        'Field method "%s"."%s" for unknown field' % (
+                            mname, attr))
+
+                    if attr.startswith('default_'):
+                        getattr(model, attr)()
+                    elif attr.startswith('order_'):
+                        tables = {None: (model.__table__(), None)}
+                        getattr(model, attr)(tables)
 
+    @with_transaction()
     def test_menu_action(self):
         'Test that menu actions are accessible to menu\'s group'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            pool = Pool()
-            Menu = pool.get('ir.ui.menu')
-            ModelData = pool.get('ir.model.data')
-
-            module_menus = ModelData.search([
-                    ('model', '=', 'ir.ui.menu'),
-                    ('module', '=', self.module),
-                    ])
-            menus = Menu.browse([mm.db_id for mm in module_menus])
-            for menu, module_menu in zip(menus, module_menus):
-                if not menu.action_keywords:
-                    continue
-                menu_groups = set(menu.groups)
-                actions_groups = reduce(operator.or_,
-                    (set(k.action.groups) for k in menu.action_keywords
-                        if k.keyword == 'tree_open'))
-                if not actions_groups:
-                    continue
-                assert menu_groups <= actions_groups, (
-                    'Menu "%(menu_xml_id)s" actions are not accessible to '
-                    '%(groups)s' % {
-                        'menu_xml_id': module_menu.fs_id,
-                        'groups': ','.join(g.name
-                            for g in menu_groups - actions_groups),
-                        })
+        pool = Pool()
+        Menu = pool.get('ir.ui.menu')
+        ModelData = pool.get('ir.model.data')
 
-    def test_model_access(self):
-        'Test missing default model access'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            Access = POOL.get('ir.model.access')
-            no_groups = {a.model.name for a in Access.search([
-                        ('group', '=', None),
-                        ])}
-            with_groups = {a.model.name for a in Access.search([
-                        ('group', '!=', None),
-                        ])}
-
-            assert no_groups >= with_groups, (
-                'Model "%(models)s" are missing a default access' % {
-                    'models': list(with_groups - no_groups),
+        module_menus = ModelData.search([
+                ('model', '=', 'ir.ui.menu'),
+                ('module', '=', self.module),
+                ])
+        menus = Menu.browse([mm.db_id for mm in module_menus])
+        for menu, module_menu in zip(menus, module_menus):
+            if not menu.action_keywords:
+                continue
+            menu_groups = set(menu.groups)
+            actions_groups = reduce(operator.or_,
+                (set(k.action.groups) for k in menu.action_keywords
+                    if k.keyword == 'tree_open'))
+            if not actions_groups:
+                continue
+            assert menu_groups <= actions_groups, (
+                'Menu "%(menu_xml_id)s" actions are not accessible to '
+                '%(groups)s' % {
+                    'menu_xml_id': module_menu.fs_id,
+                    'groups': ','.join(g.name
+                        for g in menu_groups - actions_groups),
                     })
 
+    @with_transaction()
+    def test_model_access(self):
+        'Test missing default model access'
+        pool = Pool()
+        Access = pool.get('ir.model.access')
+        no_groups = {a.model.name for a in Access.search([
+                    ('group', '=', None),
+                    ])}
+        with_groups = {a.model.name for a in Access.search([
+                    ('group', '!=', None),
+                    ])}
+
+        assert no_groups >= with_groups, (
+            'Model "%(models)s" are missing a default access' % {
+                'models': list(with_groups - no_groups),
+                })
+
+    @with_transaction()
     def test_workflow_transitions(self):
         'Test all workflow transitions exist'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            for mname, model in Pool().iterobject():
-                if not isregisteredby(model, self.module):
-                    continue
-                if not issubclass(model, Workflow):
+        for mname, model in Pool().iterobject():
+            if not isregisteredby(model, self.module):
+                continue
+            if not issubclass(model, Workflow):
+                continue
+            field = getattr(model, model._transition_state)
+            if isinstance(field.selection, (tuple, list)):
+                values = field.selection
+            else:
+                # instance method may not return all the possible values
+                if is_instance_method(model, field.selection):
                     continue
-                field = getattr(model, model._transition_state)
-                if isinstance(field.selection, (tuple, list)):
-                    values = field.selection
-                else:
-                    # instance method may not return all the possible values
-                    if is_instance_method(model, field.selection):
-                        continue
-                    values = getattr(model, field.selection)()
-                states = set(dict(values))
-                transition_states = set(chain(*model._transitions))
-                assert transition_states <= states, (
-                    ('Unknown transition states "%(states)s" '
-                        'in model "%(model)s". ') % {
-                        'states': list(transition_states - states),
-                        'model': model.__name__,
-                        })
+                values = getattr(model, field.selection)()
+            states = set(dict(values))
+            transition_states = set(chain(*model._transitions))
+            assert transition_states <= states, (
+                ('Unknown transition states "%(states)s" '
+                    'in model "%(model)s". ') % {
+                    'states': list(transition_states - states),
+                    'model': model.__name__,
+                    })
 
 
 def db_exist():
     Database = backend.get('Database')
     database = Database().connect()
-    cursor = database.cursor()
-    databases = database.list(cursor)
-    cursor.close()
-    return DB_NAME in databases
+    return DB_NAME in database.list()
 
 
 def create_db():
     if not db_exist():
-        create(DB_NAME, None, 'en_US', USER_PASSWORD)
+        create(None, DB_NAME, None, 'en_US', USER_PASSWORD)
 
 
 def drop_db():
     if db_exist():
-        drop(DB_NAME, None)
+        drop(None, DB_NAME, None)
 
 
 def drop_create():
@@ -274,11 +303,30 @@ doctest_setup = lambda test: drop_create()
 doctest_teardown = lambda test: drop_db()
 
 
+class Py23DocChecker(doctest.OutputChecker):
+    def check_output(self, want, got, optionflags):
+        if sys.version_info[0] > 2:
+            want = re.sub("u'(.*?)'", "'\\1'", want)
+            want = re.sub('u"(.*?)"', '"\\1"', want)
+        return doctest.OutputChecker.check_output(self, want, got, optionflags)
+
+doctest_checker = Py23DocChecker()
+
+
+class TestSuite(unittest.TestSuite):
+    def run(self, *args, **kwargs):
+        exist = db_exist()
+        result = super(TestSuite, self).run(*args, **kwargs)
+        if not exist:
+            drop_db()
+        return result
+
+
 def suite():
     '''
     Return test suite for other modules
     '''
-    return unittest.TestSuite()
+    return TestSuite()
 
 
 def all_suite(modules=None):
@@ -322,25 +370,7 @@ def modules_suite(modules=None, doc=True):
         else:
             continue
         for test in test_mod.suite():
-            found = False
-            for other in suite_:
-                if type(test) == type(other):
-                    if isinstance(test, doctest.DocTestCase):
-                        if str(test) == str(other):
-                            found = True
-                            break
-                    elif test._testMethodName == other._testMethodName:
-                        found = True
-                        break
-            if not found:
-                suite_.addTest(test)
-    tests = []
-    doc_tests = []
-    for test in suite_:
-        if isinstance(test, doctest.DocTestCase):
-            if doc:
-                doc_tests.append(test)
-        else:
-            tests.append(test)
-    tests.extend(doc_tests)
-    return unittest.TestSuite(tests)
+            if isinstance(test, doctest.DocTestCase) and not doc:
+                continue
+            suite_.addTest(test)
+    return suite_
diff --git a/trytond/tests/test_union.py b/trytond/tests/test_union.py
index fd05707..dd38a4f 100644
--- a/trytond/tests/test_union.py
+++ b/trytond/tests/test_union.py
@@ -2,100 +2,105 @@
 # this repository contains the full copyright notices and license terms.
 import unittest
 
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-        install_module
-from trytond.transaction import Transaction
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 
 
 class UnionMixinTestCase(unittest.TestCase):
     'Test UnionMixin'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
 
+    @with_transaction()
     def test_union(self):
         'Test union'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            Union = POOL.get('test.union')
-            for i in range(1, 4):
-                Model = POOL.get('test.model.union%s' % i)
-                for j in range(3):
-                    model = Model(name='%s - %s' % (i, j))
-                    if hasattr(Model, 'optional'):
-                        model.optional = 'optional'
-                    model.save()
-
-            self.assertEqual(len(Union.search([])), 9)
-            record, = Union.search([
-                    ('name', '=', '2 - 2'),
-                    ])
-            self.assertEqual(record.name, '2 - 2')
-            self.assertEqual(record.optional, None)
-
-            record, = Union.search([
-                    ('optional', '=', 'optional'),
-                    ], limit=1)
-            self.assertEqual(record.optional, 'optional')
-
+        pool = Pool()
+        Union = pool.get('test.union')
+
+        for i in range(1, 4):
+            Model = pool.get('test.model.union%s' % i)
+            for j in range(3):
+                model = Model(name='%s - %s' % (i, j))
+                if hasattr(Model, 'optional'):
+                    model.optional = 'optional'
+                model.save()
+
+        self.assertEqual(len(Union.search([])), 9)
+        record, = Union.search([
+                ('name', '=', '2 - 2'),
+                ])
+        self.assertEqual(record.name, '2 - 2')
+        self.assertEqual(record.optional, None)
+
+        record, = Union.search([
+                ('optional', '=', 'optional'),
+                ], limit=1)
+        self.assertEqual(record.optional, 'optional')
+
+    @with_transaction()
     def test_union_union(self):
         'Test union of union'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            Union = POOL.get('test.union.union')
-            for i in range(1, 5):
-                Model = POOL.get('test.model.union%s' % i)
-                for j in range(3):
-                    model = Model(name='%s - %s' % (i, j))
-                    model.save()
-
-            self.assertEqual(len(Union.search([])), 12)
-            record, = Union.search([
-                    ('name', '=', '2 - 2'),
-                    ])
-            self.assertEqual(record.name, '2 - 2')
-            record, = Union.search([
-                    ('name', '=', '4 - 1'),
-                    ])
-            self.assertEqual(record.name, '4 - 1')
-
+        pool = Pool()
+        Union = pool.get('test.union.union')
+
+        for i in range(1, 5):
+            Model = pool.get('test.model.union%s' % i)
+            for j in range(3):
+                model = Model(name='%s - %s' % (i, j))
+                model.save()
+
+        self.assertEqual(len(Union.search([])), 12)
+        record, = Union.search([
+                ('name', '=', '2 - 2'),
+                ])
+        self.assertEqual(record.name, '2 - 2')
+        record, = Union.search([
+                ('name', '=', '4 - 1'),
+                ])
+        self.assertEqual(record.name, '4 - 1')
+
+    @with_transaction()
     def test_union_tree(self):
         'Test union tree'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            Union = POOL.get('test.union.tree')
-            Model1 = POOL.get('test.model.union.tree1')
-            Model2 = POOL.get('test.model.union.tree2')
-
-            roots = Model1.create([{
-                        'name': 'Root1',
-                        }, {
-                        'name': 'Root2',
-                        }, {
-                        'name': 'Root3',
-                        }])
-
-            Model2.create([{
-                        'name': 'Not child',  # To shift ids
-                        }, {
-                        'name': 'Child1',
-                        'parent': roots[1].id,
-                        }, {
-                        'name': 'Child2',
-                        'parent': roots[1].id,
-                        }, {
-                        'name': 'Child3',
-                        'parent': roots[2].id,
-                        }])
-
-            uroots = Union.search([('parent', '=', None)],
-                order=[('name', 'ASC')])
-
-            self.assertEqual(len(uroots), 4)
-            names = [r.name for r in uroots]
-            self.assertEqual(names, ['Not child', 'Root1', 'Root2', 'Root3'])
-            childs = [len(r.childs) for r in uroots]
-            self.assertEqual(childs, [0, 0, 2, 1])
-            child_names = sorted((r.name for r in uroots[2].childs))
-            self.assertEqual(child_names, ['Child1', 'Child2'])
-            self.assertEqual(uroots[3].childs[0].name, 'Child3')
+        pool = Pool()
+        Union = pool.get('test.union.tree')
+        Model1 = pool.get('test.model.union.tree1')
+        Model2 = pool.get('test.model.union.tree2')
+
+        roots = Model1.create([{
+                    'name': 'Root1',
+                    }, {
+                    'name': 'Root2',
+                    }, {
+                    'name': 'Root3',
+                    }])
+
+        Model2.create([{
+                    'name': 'Not child',  # To shift ids
+                    }, {
+                    'name': 'Child1',
+                    'parent': roots[1].id,
+                    }, {
+                    'name': 'Child2',
+                    'parent': roots[1].id,
+                    }, {
+                    'name': 'Child3',
+                    'parent': roots[2].id,
+                    }])
+
+        uroots = Union.search([('parent', '=', None)],
+            order=[('name', 'ASC')])
+
+        self.assertEqual(len(uroots), 4)
+        names = [r.name for r in uroots]
+        self.assertEqual(names, ['Not child', 'Root1', 'Root2', 'Root3'])
+        childs = [len(r.childs) for r in uroots]
+        self.assertEqual(childs, [0, 0, 2, 1])
+        child_names = sorted((r.name for r in uroots[2].childs))
+        self.assertEqual(child_names, ['Child1', 'Child2'])
+        self.assertEqual(uroots[3].childs[0].name, 'Child3')
 
 
 def suite():
diff --git a/trytond/tests/test_user.py b/trytond/tests/test_user.py
index 8014845..a6a75e9 100644
--- a/trytond/tests/test_user.py
+++ b/trytond/tests/test_user.py
@@ -2,60 +2,65 @@
 # repository contains the full copyright notices and license terms.
 
 import unittest
-from trytond.transaction import Transaction
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
-    install_module
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 from trytond.res.user import bcrypt
 
 
 class UserTestCase(unittest.TestCase):
     'Test User'
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('res')
-        self.user = POOL.get('res.user')
 
     def create_user(self, login, password, hash_method=None):
-        user, = self.user.create([{
+        pool = Pool()
+        User = pool.get('res.user')
+
+        user, = User.create([{
                     'name': login,
                     'login': login,
                     }])
         if hash_method:
-            hash = getattr(self.user, 'hash_' + hash_method)
-            self.user.write([user], {
+            hash = getattr(User, 'hash_' + hash_method)
+            User.write([user], {
                     'password_hash': hash(password),
                     })
         else:
-            self.user.write([user], {
+            User.write([user], {
                     'password': password,
                     })
 
     def check_user(self, login, password):
-        user, = self.user.search([('login', '=', login)])
-        user_id = self.user.get_login(login, password)
+        pool = Pool()
+        User = pool.get('res.user')
+
+        user, = User.search([('login', '=', login)])
+        user_id = User.get_login(login, password)
         self.assertEqual(user_id, user.id)
 
-        bad_user_id = self.user.get_login(login, password + 'wrong')
+        bad_user_id = User.get_login(login, password + 'wrong')
         self.assertEqual(bad_user_id, 0)
 
-    def test0010test_hash(self):
+    @with_transaction()
+    def test_test_hash(self):
         'Test default hash password'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            self.create_user('user', '12345')
-            self.check_user('user', '12345')
+        self.create_user('user', '12345')
+        self.check_user('user', '12345')
 
-    def test0011test_sha1(self):
+    @with_transaction()
+    def test_test_sha1(self):
         'Test sha1 password'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            self.create_user('user', '12345', 'sha1')
-            self.check_user('user', '12345')
+        self.create_user('user', '12345', 'sha1')
+        self.check_user('user', '12345')
 
     @unittest.skipIf(bcrypt is None, 'requires bcrypt')
-    def test0012test_bcrypt(self):
+    @with_transaction()
+    def test_test_bcrypt(self):
         'Test bcrypt password'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            self.create_user('user', '12345', 'bcrypt')
-            self.check_user('user', '12345')
+        self.create_user('user', '12345', 'bcrypt')
+        self.check_user('user', '12345')
 
 
 def suite():
diff --git a/trytond/tests/test_webdav.py b/trytond/tests/test_webdav.py
deleted file mode 100644
index 4957b36..0000000
--- a/trytond/tests/test_webdav.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import unittest
-
-from .test_tryton import ModuleTestCase
-
-
-class WebDAVTestCase(ModuleTestCase):
-    'Test ir module'
-    module = 'webdav'
-
-
-def suite():
-    return unittest.TestLoader().loadTestsFromTestCase(WebDAVTestCase)
diff --git a/trytond/tests/test_wizard.py b/trytond/tests/test_wizard.py
index 4e99bed..aba0bac 100644
--- a/trytond/tests/test_wizard.py
+++ b/trytond/tests/test_wizard.py
@@ -1,95 +1,108 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of this
 # repository contains the full copyright notices and license terms.
 import unittest
-from trytond.tests.test_tryton import (POOL, DB_NAME, USER, CONTEXT,
-    install_module)
+from trytond.tests.test_tryton import install_module, with_transaction
 from trytond.transaction import Transaction
+from trytond.pool import Pool
 
 
 class WizardTestCase(unittest.TestCase):
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.wizard = POOL.get('test.test_wizard', type='wizard')
-        self.session = POOL.get('ir.session.wizard')
-        self.group = POOL.get('res.group')
 
-    def test0010create(self):
+    @with_transaction()
+    def test_create(self):
         'Create Session Wizard'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            session_id, start_state, end_state = self.wizard.create()
-            self.assertEqual(start_state, 'start')
-            self.assertEqual(end_state, 'end')
-            self.assert_(session_id)
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
 
-    def test0020delete(self):
+        session_id, start_state, end_state = Wizard.create()
+        self.assertEqual(start_state, 'start')
+        self.assertEqual(end_state, 'end')
+        self.assert_(session_id)
+
+    @with_transaction()
+    def test_delete(self):
         'Delete Session Wizard'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            session_id, _, _ = self.wizard.create()
-            self.wizard.delete(session_id)
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
+
+        session_id, _, _ = Wizard.create()
+        Wizard.delete(session_id)
 
-    def test0030session(self):
+    @with_transaction()
+    def test_session(self):
         'Session Wizard'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            session_id, = self.session.create([{}])
-            session = self.wizard(session_id)
-            self.assertEqual(session.start.id, None)
-            self.assertRaises(AttributeError, getattr, session.start, 'name')
-            self.assertEqual(hasattr(session.start, 'name'), False)
-            session.start.name = 'Test'
-            self.assertRaises(AttributeError, getattr, session.start, 'user')
-            self.assertEqual(hasattr(session.start, 'user'), False)
-            session.start.user = USER
-            group_a, = self.group.create([{
-                        'name': 'Group A',
-                        }])
-            group_b, = self.group.create([{
-                        'name': 'Group B',
-                        }])
-            session.start.groups = [
-                group_a,
-                group_b,
-                ]
-            session._save()
-            session = self.wizard(session_id)
-            self.assertEqual(session.start.id, None)
-            self.assertEqual(session.start.name, 'Test')
-            self.assertEqual(session.start.user.id, USER)
-            self.assertEqual(session.start.user.login, 'admin')
-            group_a, group_b = session.start.groups
-            self.assertEqual(group_a.name, 'Group A')
-            self.assertEqual(group_b.name, 'Group B')
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
+        Session = pool.get('ir.session.wizard')
+        Group = pool.get('res.group')
+        transaction = Transaction()
 
-    def test0040execute(self):
+        session_id, = Session.create([{}])
+        session = Wizard(session_id)
+        self.assertEqual(session.start.id, None)
+        self.assertRaises(AttributeError, getattr, session.start, 'name')
+        self.assertEqual(hasattr(session.start, 'name'), False)
+        session.start.name = 'Test'
+        self.assertRaises(AttributeError, getattr, session.start, 'user')
+        self.assertEqual(hasattr(session.start, 'user'), False)
+        session.start.user = transaction.user
+        group_a, = Group.create([{
+                    'name': 'Group A',
+                    }])
+        group_b, = Group.create([{
+                    'name': 'Group B',
+                    }])
+        session.start.groups = [
+            group_a,
+            group_b,
+            ]
+        session._save()
+        session = Wizard(session_id)
+        self.assertEqual(session.start.id, None)
+        self.assertEqual(session.start.name, 'Test')
+        self.assertEqual(session.start.user.id, transaction.user)
+        self.assertEqual(session.start.user.login, 'admin')
+        group_a, group_b = session.start.groups
+        self.assertEqual(group_a.name, 'Group A')
+        self.assertEqual(group_b.name, 'Group B')
+
+    @with_transaction()
+    def test_execute(self):
         'Execute Wizard'
-        with Transaction().start(DB_NAME, USER, CONTEXT):
-            session_id, start_state, end_state = self.wizard.create()
-            result = self.wizard.execute(session_id, {}, start_state)
-            self.assertEqual(result.keys(), ['view'])
-            self.assertEqual(result['view']['defaults'], {
-                    'name': 'Test wizard',
-                    })
-            self.assertEqual(result['view']['buttons'], [
-                    {
-                        'state': 'end',
-                        'states': '{}',
-                        'icon': 'tryton-cancel',
-                        'default': False,
-                        'string': 'Cancel',
-                        },
-                    {
-                        'state': 'next_',
-                        'states': '{}',
-                        'icon': 'tryton-next',
-                        'default': True,
-                        'string': 'Next',
-                        },
-                    ])
-            result = self.wizard.execute(session_id, {
-                    start_state: {
-                        'name': 'Test Update',
-                        }}, 'next_')
-            self.assertEqual(len(result['actions']), 1)
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
+
+        session_id, start_state, end_state = Wizard.create()
+        result = Wizard.execute(session_id, {}, start_state)
+        self.assertEqual(result.keys(), ['view'])
+        self.assertEqual(result['view']['defaults'], {
+                'name': 'Test wizard',
+                })
+        self.assertEqual(result['view']['buttons'], [
+                {
+                    'state': 'end',
+                    'states': '{}',
+                    'icon': 'tryton-cancel',
+                    'default': False,
+                    'string': 'Cancel',
+                    },
+                {
+                    'state': 'next_',
+                    'states': '{}',
+                    'icon': 'tryton-next',
+                    'default': True,
+                    'string': 'Next',
+                    },
+                ])
+        result = Wizard.execute(session_id, {
+                start_state: {
+                    'name': 'Test Update',
+                    }}, 'next_')
+        self.assertEqual(len(result['actions']), 1)
 
 
 def suite():
diff --git a/trytond/tests/test_workflow.py b/trytond/tests/test_workflow.py
index 74adbdb..b18d9a7 100644
--- a/trytond/tests/test_workflow.py
+++ b/trytond/tests/test_workflow.py
@@ -3,30 +3,32 @@
 
 import unittest
 
-from trytond.transaction import Transaction
-from trytond.tests.test_tryton import (POOL, DB_NAME, USER, CONTEXT,
-    install_module)
+from trytond.tests.test_tryton import install_module, with_transaction
+from trytond.pool import Pool
 
 
 class WorkflowTestCase(unittest.TestCase):
 
-    def setUp(self):
+    @classmethod
+    def setUpClass(cls):
         install_module('tests')
-        self.workflow = POOL.get('test.workflowed')
 
     # TODO add test for Workflow.transition
-    def test0010transition(self):
+    @with_transaction()
+    def test_transition(self):
         'Test transition'
-        with Transaction().start(DB_NAME, USER, context=CONTEXT):
-            wkf, = self.workflow.create([{}])
+        pool = Pool()
+        Workflowed = pool.get('test.workflowed')
 
-            self.workflow.run([wkf])
-            self.assertEqual(wkf.state, 'running')
+        wkf, = Workflowed.create([{}])
 
-            wkf.state = 'end'
-            wkf.save()
-            self.workflow.run([wkf])
-            self.assertEqual(wkf.state, 'end')
+        Workflowed.run([wkf])
+        self.assertEqual(wkf.state, 'running')
+
+        wkf.state = 'end'
+        wkf.save()
+        Workflowed.run([wkf])
+        self.assertEqual(wkf.state, 'end')
 
 
 def suite():
diff --git a/trytond/tools/__init__.py b/trytond/tools/__init__.py
index c5c9170..5854f45 100644
--- a/trytond/tools/__init__.py
+++ b/trytond/tools/__init__.py
@@ -1,5 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+from itertools import izip
+
 from .misc import *
 from .datetime_strftime import *
 from .decimal_ import *
@@ -8,3 +10,13 @@ from .decimal_ import *
 class ClassProperty(property):
     def __get__(self, cls, owner):
         return self.fget.__get__(None, owner)()
+
+
+def cursor_dict(cursor, size=None):
+    size = cursor.arraysize if size is None else size
+    while True:
+        rows = cursor.fetchmany(size)
+        if not rows:
+            break
+        for row in rows:
+            yield {d[0]: v for d, v in izip(cursor.description, row)}
diff --git a/trytond/tools/decimal_.py b/trytond/tools/decimal_.py
index ee156c0..08d36dd 100644
--- a/trytond/tools/decimal_.py
+++ b/trytond/tools/decimal_.py
@@ -1,36 +1,73 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-import tokenize
-from io import StringIO
+import sys
+from tokenize import *
+from io import BytesIO, StringIO
 
 # code snippet taken from http://docs.python.org/library/tokenize.html
 
 
-def decistmt(s):
-    """Substitute Decimals for floats in a string of statements.
-
-    >>> from decimal import Decimal
-    >>> s = 'print +21.3e-5*-.1234/81.7'
-    >>> decistmt(s)
-    u"print +Decimal (u'21.3e-5')*-Decimal (u'.1234')/Decimal (u'81.7')"
-
-    >>> exec(s)
-    -3.21716034272e-07
-    >>> exec(decistmt(s))
-    -3.217160342717258261933904529E-7
-    """
-    result = []
-    # tokenize the string
-    g = tokenize.generate_tokens(StringIO(s.decode('utf-8')).readline)
-    for toknum, tokval, _, _, _ in g:
-        # replace NUMBER tokens
-        if toknum == tokenize.NUMBER and '.' in tokval:
-            result.extend([
-                (tokenize.NAME, 'Decimal'),
-                (tokenize.OP, '('),
-                (tokenize.STRING, repr(tokval)),
-                (tokenize.OP, ')')
-            ])
-        else:
-            result.append((toknum, tokval))
-    return tokenize.untokenize(result)
+if sys.version_info < (3,):
+    def decistmt(s):
+        """Substitute Decimals for floats in a string of statements.
+
+        >>> from decimal import Decimal
+        >>> s = 'print +21.3e-5*-.1234/81.7'
+        >>> decistmt(s)
+        u"print +Decimal (u'21.3e-5')*-Decimal (u'.1234')/Decimal (u'81.7')"
+
+        >>> exec(s)
+        -3.21716034272e-07
+        >>> exec(decistmt(s))
+        -3.217160342717258261933904529E-7
+
+        """
+        result = []
+        g = generate_tokens(StringIO(s.decode('utf-8')).readline)   # tokenize the string
+        for toknum, tokval, _, _, _ in g:
+            if toknum == NUMBER and '.' in tokval:  # replace NUMBER tokens
+                result.extend([
+                    (NAME, 'Decimal'),
+                    (OP, '('),
+                    (STRING, repr(tokval)),
+                    (OP, ')')
+                ])
+            else:
+                result.append((toknum, tokval))
+        return untokenize(result)
+else:
+    def decistmt(s):
+        """Substitute Decimals for floats in a string of statements.
+
+        >>> from decimal import Decimal
+        >>> s = 'print(+21.3e-5*-.1234/81.7)'
+        >>> decistmt(s)
+        "print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
+
+        The format of the exponent is inherited from the platform C library.
+        Known cases are "e-007" (Windows) and "e-07" (not Windows).  Since
+        we're only showing 12 digits, and the 13th isn't close to 5, the
+        rest of the output should be platform-independent.
+
+        >>> exec(s) #doctest: +ELLIPSIS
+        -3.217160342717258e-0...7
+
+        Output from calculations with Decimal should be identical across all
+        platforms.
+
+        >>> exec(decistmt(s))
+        -3.217160342717258261933904529E-7
+        """
+        result = []
+        g = tokenize(BytesIO(s.encode('utf-8')).readline)  # tokenize the string
+        for toknum, tokval, _, _, _ in g:
+            if toknum == NUMBER and '.' in tokval:  # replace NUMBER tokens
+                result.extend([
+                    (NAME, 'Decimal'),
+                    (OP, '('),
+                    (STRING, repr(tokval)),
+                    (OP, ')')
+                ])
+            else:
+                result.append((toknum, tokval))
+        return untokenize(result).decode('utf-8')
diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py
index 16f65fa..b1ada39 100644
--- a/trytond/tools/misc.py
+++ b/trytond/tools/misc.py
@@ -7,18 +7,16 @@ Miscelleanous tools used by tryton
 import os
 import sys
 import subprocess
-from threading import local
-import smtplib
 from array import array
 from itertools import islice
 import types
-import urllib
+import io
+import warnings
 
 from sql import Literal
 from sql.operators import Or
 
 from trytond.const import OPERATORS
-from trytond.config import config, parse_uri
 
 
 def find_in_path(name):
@@ -50,11 +48,14 @@ def exec_command_pipe(name, *args, **kwargs):
         stdout=subprocess.PIPE, env=child_env)
 
 
-def file_open(name, mode="r", subdir='modules'):
+def file_open(name, mode="r", subdir='modules', encoding=None):
     """Open a file from the root dir, using a subdir folder."""
     from trytond.modules import EGG_MODULES
-    root_path = os.path.dirname(os.path.dirname(os.path.abspath(
-                unicode(__file__, sys.getfilesystemencoding()))))
+    if sys.version_info < (3,):
+        filename = __file__.decode(sys.getfilesystemencoding())
+    else:
+        filename = __file__
+    root_path = os.path.dirname(os.path.dirname(os.path.abspath(filename)))
 
     egg_name = False
     if subdir == 'modules':
@@ -82,7 +83,6 @@ def file_open(name, mode="r", subdir='modules'):
         if (subdir == 'modules'
                 and (name.startswith('ir' + os.sep)
                     or name.startswith('res' + os.sep)
-                    or name.startswith('webdav' + os.sep)
                     or name.startswith('tests' + os.sep))):
             name = os.path.join(root_path, name)
         else:
@@ -92,7 +92,7 @@ def file_open(name, mode="r", subdir='modules'):
 
     for i in (name, egg_name):
         if i and os.path.isfile(i):
-            return open(i, mode)
+            return io.open(i, mode, encoding=encoding)
 
     raise IOError('File not found : %s ' % name)
 
@@ -104,21 +104,11 @@ def get_smtp_server():
     :return: A SMTP instance. The quit() method must be call when all
     the calls to sendmail() have been made.
     """
-    uri = parse_uri(config.get('email', 'uri'))
-    if uri.scheme.startswith('smtps'):
-        smtp_server = smtplib.SMTP_SSL(uri.hostname, uri.port)
-    else:
-        smtp_server = smtplib.SMTP(uri.hostname, uri.port)
-
-    if 'tls' in uri.scheme:
-        smtp_server.starttls()
-
-    if uri.username and uri.password:
-        smtp_server.login(
-            urllib.unquote_plus(uri.username),
-            urllib.unquote_plus(uri.password))
-
-    return smtp_server
+    from ..sendmail import _get_smtp_server
+    warnings.warn(
+        'get_smtp_server is deprecated use trytond.sendmail',
+        DeprecationWarning)
+    return _get_smtp_server()
 
 
 def memoize(maxsize):
@@ -201,103 +191,6 @@ def mod10r(number):
     return result + str((10 - report) % 10)
 
 
-class LocalDict(local):
-
-    def __init__(self):
-        super(LocalDict, self).__init__()
-        self._dict = {}
-
-    def __str__(self):
-        return str(self._dict)
-
-    def __repr__(self):
-        return str(self._dict)
-
-    def clear(self):
-        return self._dict.clear()
-
-    def keys(self):
-        return self._dict.keys()
-
-    def __setitem__(self, i, y):
-        self._dict.__setitem__(i, y)
-
-    def __getitem__(self, i):
-        return self._dict.__getitem__(i)
-
-    def copy(self):
-        return self._dict.copy()
-
-    def iteritems(self):
-        return self._dict.iteritems()
-
-    def iterkeys(self):
-        return self._dict.iterkeys()
-
-    def itervalues(self):
-        return self._dict.itervalues()
-
-    def pop(self, k, d=None):
-        return self._dict.pop(k, d)
-
-    def popitem(self):
-        return self._dict.popitem()
-
-    def setdefault(self, k, d=None):
-        return self._dict.setdefault(k, d)
-
-    def update(self, E, **F):
-        return self._dict.update(E, F)
-
-    def values(self):
-        return self._dict.values()
-
-    def get(self, k, d=None):
-        return self._dict.get(k, d)
-
-    def has_key(self, k):
-        return k in self._dict
-
-    def items(self):
-        return self._dict.items()
-
-    def __cmp__(self, y):
-        return self._dict.__cmp__(y)
-
-    def __contains__(self, k):
-        return self._dict.__contains__(k)
-
-    def __delitem__(self, y):
-        return self._dict.__delitem__(y)
-
-    def __eq__(self, y):
-        return self._dict.__eq__(y)
-
-    def __ge__(self, y):
-        return self._dict.__ge__(y)
-
-    def __gt__(self, y):
-        return self._dict.__gt__(y)
-
-    def __hash__(self):
-        return self._dict.__hash__()
-
-    def __iter__(self):
-        return self._dict.__iter__()
-
-    def __le__(self, y):
-        return self._dict.__le__(y)
-
-    def __len__(self):
-        return self._dict.__len__()
-
-    def __lt__(self, y):
-        return self._dict.__lt__(y)
-
-    def __ne__(self, y):
-        return self._dict.__ne__(y)
-
-
 def reduce_ids(field, ids):
     '''
     Return a small SQL expression for the list of ids and the sql column
@@ -371,7 +264,7 @@ def grouped_slice(records, count=None):
     'Grouped slice'
     from trytond.transaction import Transaction
     if count is None:
-        count = Transaction().cursor.IN_MAX
+        count = Transaction().database.IN_MAX
     for i in xrange(0, len(records), count):
         yield islice(records, i, i + count)
 
diff --git a/trytond/transaction.py b/trytond/transaction.py
index ef4ca63..754b90f 100644
--- a/trytond/transaction.py
+++ b/trytond/transaction.py
@@ -1,22 +1,13 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+import logging
 from threading import local
 from sql import Flavor
 
-from trytond.tools.singleton import Singleton
 from trytond import backend
+from trytond.config import config
 
-
-class _TransactionManager(object):
-    '''
-    Manage transaction start/stop
-    '''
-
-    def __enter__(self):
-        return Transaction()
-
-    def __exit__(self, type, value, traceback):
-        Transaction().stop()
+logger = logging.getLogger(__name__)
 
 
 class _AttributeManager(object):
@@ -35,30 +26,25 @@ class _AttributeManager(object):
             setattr(Transaction(), name, value)
 
 
-class _CursorManager(object):
-    '''
-    Manage cursor of transaction
-    '''
-
-    def __init__(self, cursor):
-        self.cursor = cursor
+class _Local(local):
 
-    def __enter__(self):
-        return Transaction()
+    def __init__(self):
+        # Transaction stack control
+        self.transactions = []
 
-    def __exit__(self, type, value, traceback):
-        Transaction().cursor.close()
-        Transaction().cursor = self.cursor
 
-
-class Transaction(local):
+class Transaction(object):
     '''
     Control the transaction
     '''
-    __metaclass__ = Singleton
 
-    cursor = None
+    _local = _Local()
+
+    cache_keys = {'language', 'fuzzy_translation', '_datetime'}
+
     database = None
+    readonly = False
+    connection = None
     close = None
     user = None
     context = None
@@ -67,6 +53,24 @@ class Transaction(local):
     delete = None  # TODO check to merge with delete_records
     timestamp = None
 
+    def __new__(cls, new=False):
+        transactions = cls._local.transactions
+        if new or not transactions:
+            instance = super(Transaction, cls).__new__(cls)
+            instance.cache = {}
+            transactions.append(instance)
+        else:
+            instance = transactions[-1]
+        return instance
+
+    def get_cache(self):
+        from trytond.cache import LRUDict
+        keys = tuple(((key, self.context[key])
+                for key in sorted(self.cache_keys)
+                if key in self.context))
+        return self.cache.setdefault((self.user, keys),
+            LRUDict(config.getint('cache', 'model')))
+
     def start(self, database_name, user, readonly=False, context=None,
             close=False, autocommit=False):
         '''
@@ -75,7 +79,6 @@ class Transaction(local):
         Database = backend.get('Database')
         assert self.user is None
         assert self.database is None
-        assert self.cursor is None
         assert self.close is None
         assert self.context is None
         if not database_name:
@@ -83,11 +86,11 @@ class Transaction(local):
         else:
             database = Database(database_name).connect()
         Flavor.set(Database.flavor)
-        cursor = database.cursor(readonly=readonly,
-            autocommit=autocommit)
         self.user = user
         self.database = database
-        self.cursor = cursor
+        self.readonly = readonly
+        self.connection = database.get_connection(readonly=readonly,
+            autocommit=autocommit)
         self.close = close
         self.context = context or {}
         self.create_records = {}
@@ -95,24 +98,40 @@ class Transaction(local):
         self.delete = {}
         self.timestamp = {}
         self.counter = 0
-        return _TransactionManager()
+        self._datamanagers = []
+        return self
 
-    def stop(self):
-        '''
-        Stop transaction
-        '''
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        transactions = self._local.transactions
         try:
-            self.cursor.close(close=self.close)
+            if transactions.count(self) == 1:
+                try:
+                    try:
+                        if type is None and not self.readonly:
+                            self.commit()
+                        else:
+                            self.rollback()
+                    finally:
+                        self.database.put_connection(
+                            self.connection, self.close)
+                finally:
+                    self.database = None
+                    self.readonly = False
+                    self.connection = None
+                    self.close = None
+                    self.user = None
+                    self.context = None
+                    self.create_records = None
+                    self.delete_records = None
+                    self.delete = None
+                    self.timestamp = None
+                    self._datamanagers = []
         finally:
-            self.cursor = None
-            self.database = None
-            self.close = None
-            self.user = None
-            self.context = None
-            self.create_records = None
-            self.delete_records = None
-            self.delete = None
-            self.timestamp = None
+            current_instance = transactions.pop()
+        assert current_instance is self, transactions
 
     def set_context(self, context=None, **kwargs):
         if context is None:
@@ -143,17 +162,52 @@ class Transaction(local):
         self.user = user
         return manager
 
-    def set_cursor(self, cursor):
-        manager = _AttributeManager(cursor=self.cursor)
-        self.cursor = cursor
-        return manager
+    def set_current_transaction(self, transaction):
+        self._local.transactions.append(transaction)
+        return transaction
 
-    def new_cursor(self, autocommit=False, readonly=False):
-        Database = backend.get('Database')
-        manager = _CursorManager(self.cursor)
-        database = Database(self.cursor.database_name).connect()
-        self.cursor = database.cursor(autocommit=autocommit, readonly=readonly)
-        return manager
+    def new_transaction(self, autocommit=False, readonly=False):
+        transaction = Transaction(new=True)
+        return transaction.start(self.database.name, self.user,
+            context=self.context, close=self.close, readonly=readonly,
+            autocommit=autocommit)
+
+    def commit(self):
+        try:
+            if self._datamanagers:
+                for datamanager in self._datamanagers:
+                    datamanager.tpc_begin(self)
+                for datamanager in self._datamanagers:
+                    datamanager.commit(self)
+                for datamanager in self._datamanagers:
+                    datamanager.tpc_vote(self)
+            self.connection.commit()
+        except:
+            self.rollback()
+            raise
+        else:
+            try:
+                for datamanager in self._datamanagers:
+                    datamanager.tpc_finish(self)
+            except:
+                logger.critical('A datamanager raised an exception in'
+                    ' tpc_finish, the data might be inconsistant',
+                    exc_info=True)
+
+    def rollback(self):
+        for cache in self.cache.itervalues():
+            cache.clear()
+        for datamanager in self._datamanagers:
+            datamanager.tpc_abort(self)
+        self.connection.rollback()
+
+    def join(self, datamanager):
+        try:
+            idx = self._datamanagers.index(datamanager)
+            return self._datamanagers[idx]
+        except ValueError:
+            self._datamanagers.append(datamanager)
+            return datamanager
 
     @property
     def language(self):
diff --git a/trytond/url.py b/trytond/url.py
index 2e40fad..80f445e 100644
--- a/trytond/url.py
+++ b/trytond/url.py
@@ -10,10 +10,10 @@ from trytond.transaction import Transaction
 
 __all__ = ['URLMixin']
 
-HOSTNAME = (config.get('jsonrpc', 'hostname')
-    or unicode(socket.getfqdn(), 'utf8'))
-HOSTNAME = '.'.join(encodings.idna.ToASCII(part) if part else ''
-    for part in HOSTNAME.split('.'))
+HOSTNAME = (config.get('web', 'hostname')
+    or socket.getfqdn())
+HOSTNAME = '.'.join(encodings.idna.ToASCII(part).decode('ascii')
+    if part else '' for part in HOSTNAME.split('.'))
 
 
 class URLAccessor(object):
@@ -34,7 +34,7 @@ class URLAccessor(object):
             raise NotImplementedError
 
         url_part['name'] = cls.__name__
-        url_part['database'] = Transaction().cursor.database_name
+        url_part['database'] = Transaction().database.name
 
         local_part = urllib.quote('%(database)s/%(type)s/%(name)s' % url_part)
         if isinstance(inst, Model) and inst.id:
diff --git a/trytond/webdav/__init__.py b/trytond/webdav/__init__.py
deleted file mode 100644
index c1fe716..0000000
--- a/trytond/webdav/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-from ..pool import Pool
-from .webdav import *
-
-
-def register():
-    Pool.register(
-        Collection,
-        Share,
-        Attachment,
-        module='webdav', type_='model')
diff --git a/trytond/webdav/locale/bg_BG.po b/trytond/webdav/locale/bg_BG.po
deleted file mode 100644
index 3c7cb47..0000000
--- a/trytond/webdav/locale/bg_BG.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "Името на колекцията трябва да уникално вътре в колекцията!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Път"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Споделени папки"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Наследници"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Пълно име"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Създадено на"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Създадено от"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Домейн"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Модел"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Име"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Родител"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Име"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Променено на"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Променено от"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Създадено на"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Създадено от"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Крайна дата"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Ключ"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Бележка"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Път"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Име"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Потребител"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Променено на"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Променено от"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Колекции"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Колекции"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Споделени папки"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Колекции"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Колекции"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Споделени папки"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Колекция"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Споделена папка"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Колекция"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Колекции"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Споделена папка"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Споделени папки"
diff --git a/trytond/webdav/locale/ca_ES.po b/trytond/webdav/locale/ca_ES.po
deleted file mode 100644
index 673dcfd..0000000
--- a/trytond/webdav/locale/ca_ES.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No podeu crear un adjunt anomenat \"%(attachment)s\" al directori "
-"\"%(collection)s\" perquè ja existeix un directori amb aquest nom."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "El nom del directori ha de ser únic dins del directori."
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No podeu crear un directori amb el nom \"%(parent)s\" dins del directori "
-"\"%(child)s\" perquè ja existeix un altre amb aquest nom."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Directoris compartits"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Fills"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nom complet"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Data creació"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Usuari creació"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Domini"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Model"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Pare"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Data modificació"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Usuari modificació"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Data creació"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Usuari creació"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Data expiració"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clau"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuari"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Data modificació"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Usuari modificació"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Directoris"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Directoris"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Directoris compartits"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Directoris"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Directoris"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Directoris compartits"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Directori"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Directori compartit"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Directori"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Directoris"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Directori compartit"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Directoris compartits"
diff --git a/trytond/webdav/locale/cs_CZ.po b/trytond/webdav/locale/cs_CZ.po
deleted file mode 100644
index d437783..0000000
--- a/trytond/webdav/locale/cs_CZ.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr ""
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr ""
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr ""
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr ""
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr ""
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr ""
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/de_DE.po b/trytond/webdav/locale/de_DE.po
deleted file mode 100644
index 5bc1e2b..0000000
--- a/trytond/webdav/locale/de_DE.po
+++ /dev/null
@@ -1,189 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"Erstellung von Anhang \"%(attachment)s\" in Sammlung \"%(collection)s\" "
-"nicht möglich, weil es bereits eine Sammlung mit diesem Namen gibt"
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-"Der Name einer untergeordneten Sammlung kann nur einmal in einer Sammlung "
-"vergeben werden!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"Sammlung \"%(parent)s\" in Sammlung \"%(child)s\" kann nicht angelegt "
-"werden, weil es bereits eine Datei mit diesem Namen gibt."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Pfad"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Freigaben"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Untergeordnet (Sammlungen)"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Vollständiger Name"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Erstellungsdatum"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Erstellt durch"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Wertebereich (Domain)"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modell"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Name"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Übergeordnet (Sammlung)"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Name"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Zuletzt geändert"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Letzte Änderung durch"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Erstellungsdatum"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Erstellt durch"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Ablaufdatum"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Schlüssel"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Notiz"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Pfad"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Name"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Benutzer"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Zuletzt geändert"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Letzte Änderung durch"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Sammlungen"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Sammlungen"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Freigaben"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Sammlungen"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Sammlungen"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Freigaben"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Sammlung"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Freigabe"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Sammlung"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Sammlungen"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Freigabe"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Freigaben"
diff --git a/trytond/webdav/locale/es_AR.po b/trytond/webdav/locale/es_AR.po
deleted file mode 100644
index 3174fa4..0000000
--- a/trytond/webdav/locale/es_AR.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No puede crear un archivo adjunto llamado «%(attachment)s» en la colección "
-"«%(collection)s» porque ya existe una colección con este nombre."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "¡El nombre de la colección debe ser único dentro de dicha colección!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No puede crear una colección denominada «%(parent)s» en la colección "
-"«%(child)s» porque ya existe un archivo con ese nombre."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Recursos compartidos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Hijos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nombre completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Dominio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Padre"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Fecha vencimiento"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuario"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Recurso compartido"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Recursos compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Recurso compartido"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Recurso compartido"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Recursos compartidos"
diff --git a/trytond/webdav/locale/es_CO.po b/trytond/webdav/locale/es_CO.po
deleted file mode 100644
index 3e97429..0000000
--- a/trytond/webdav/locale/es_CO.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No puede crear un adjunto nombrado \"%(attachments)s\" en el repositorio "
-"\"%(collections)s\" porque hay actualmente un repositorio con ese nombre."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "El nombre de la colección debe ser único dentro de dicha colección!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No puede crear una colección llamada \"%(parent)s\" en la colección "
-"\"%(child)s\" porque existe un archivo con el mismo nombre."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Recuros Compartidos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Hijos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nombre Completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Fecha de Creación"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Creado por Usuario"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Dominio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Padre"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Fecha de Modificación"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Modificado por Usuario"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Fecha de Creación"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Creado por Usuario"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Fecha de Expiración"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuario"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Fecha de Modificación"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Modificado por Usuario"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Recuros Compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Recuros Compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Recurso Compartido"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Recurso Compartido"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Recuros Compartidos"
diff --git a/trytond/webdav/locale/es_EC.po b/trytond/webdav/locale/es_EC.po
deleted file mode 100644
index eeadcc9..0000000
--- a/trytond/webdav/locale/es_EC.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No puede crear un adjunto llamado \"%(attachment)s\" en la colección "
-"\"%(collection)s\" porque ya existe una colección con ese nombre."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "¡El nombre de la colección debe ser único dentro de una colección!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No puede crear una colección llamada \"%(parent)s\" en la colección "
-"\"%(child)s\" porque ya existe un archivo con ese nombre."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Recursos compartidos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Hijos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nombre completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Fecha de creación"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Creado por usuario"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Dominio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Padre"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Fecha de modificación"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Modificado por usuario"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Fecha de creación"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Creado por usuario"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Fecha de expiración"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuario"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Fecha de modificación"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Modificado por usuario"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Recursos compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Recursos compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Recurso compartido"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Colección"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Colecciones"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Recurso compartido"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Recursos compartidos"
diff --git a/trytond/webdav/locale/es_ES.po b/trytond/webdav/locale/es_ES.po
deleted file mode 100644
index 2dbda01..0000000
--- a/trytond/webdav/locale/es_ES.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No puede crear un adjunto llamado \"%(attachment)s\" en el directorio "
-"\"%(collection)s\" porque ya existe un directorio con este nombre."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "El nombre del directorio debe ser único dentro del directorio."
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No puede crear un directorio con el nombre \"%(parent)s\" en el directorio "
-"\"%(child)s\" porque ya existe otro con ese nombre."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Hijos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nombre completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Dominio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Padre"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Fecha expiración"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuario"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Directorio"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Directorio compartido"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Directorio"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Directorio compartido"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Directorios compartidos"
diff --git a/trytond/webdav/locale/es_MX.po b/trytond/webdav/locale/es_MX.po
deleted file mode 100644
index 2eaf8ef..0000000
--- a/trytond/webdav/locale/es_MX.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"No puede crear un adjunto llamado \"%(attachment)s\" en el directorio "
-"\"%(collection)s\" porque ya existe un directorio con este nombre."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "El nombre del directorio debe ser único dentro del directorio."
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"No puede crear un directorio con el nombre \"%(parent)s\" en el directorio "
-"\"%(child)s\" porque ya existe otro con ese nombre."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Hijos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nombre completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Dominio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Padre"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Fecha creación"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Usuario creación"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Fecha expiración"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Ruta"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nombre"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuario"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Fecha modificación"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Usuario modificación"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Directorios"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Directorios compartidos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Directorio"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Directorio compartido"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/fr_FR.po b/trytond/webdav/locale/fr_FR.po
deleted file mode 100644
index 512036e..0000000
--- a/trytond/webdav/locale/fr_FR.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"Vous ne pouvez pas créer un attachement nommé « %(attachment)s » dans la "
-"collection « %(collection)s » car il y a déjà une collection avec ce nom."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "Le nom de collection doit être unique au sein d'une collection !"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"Vous ne pouvez pas créer une collection nommée « %(parent)s » dans la "
-"collection « %(child)s » car il y a déjà un fichier avec ce nom."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Chemin"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Partages"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Enfants"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nom complet"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Date de création"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Créé par"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Domaine"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modèle"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Parent"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Date de mise à jour"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Mis à jour par"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Date de création"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Créé par"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Date d'expiration"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Clé"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Note"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Chemin"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nom"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Utilisateur"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Date de mise à jour"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Mis à jour par"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Collections"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Collections"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Partages"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Collections"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Collections"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Partages"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Collection"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Partage"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Collection"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Collections"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Partage"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Partages"
diff --git a/trytond/webdav/locale/hu_HU.po b/trytond/webdav/locale/hu_HU.po
deleted file mode 100644
index d437783..0000000
--- a/trytond/webdav/locale/hu_HU.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr ""
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr ""
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr ""
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr ""
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr ""
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr ""
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/it_IT.po b/trytond/webdav/locale/it_IT.po
deleted file mode 100644
index d437783..0000000
--- a/trytond/webdav/locale/it_IT.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr ""
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr ""
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr ""
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr ""
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr ""
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr ""
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/ja_JP.po b/trytond/webdav/locale/ja_JP.po
deleted file mode 100644
index d437783..0000000
--- a/trytond/webdav/locale/ja_JP.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr ""
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr ""
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr ""
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr ""
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr ""
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr ""
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/lt_LT.po b/trytond/webdav/locale/lt_LT.po
deleted file mode 100644
index d437783..0000000
--- a/trytond/webdav/locale/lt_LT.po
+++ /dev/null
@@ -1,183 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr ""
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr ""
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr ""
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr ""
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr ""
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr ""
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr ""
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr ""
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr ""
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/nl_NL.po b/trytond/webdav/locale/nl_NL.po
deleted file mode 100644
index 139c028..0000000
--- a/trytond/webdav/locale/nl_NL.po
+++ /dev/null
@@ -1,194 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "De naam van de verzameling moet uniek zijn binnen de verzameling!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-
-#, fuzzy
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Pad"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr ""
-
-#, fuzzy
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Onderliggende niveaus"
-
-#, fuzzy
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Volledige naam"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Domein"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Model"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Naam"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Bovenliggend niveau"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Naam"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr ""
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr ""
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr ""
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr ""
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr ""
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr ""
-
-#, fuzzy
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Aantekening"
-
-#, fuzzy
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Pad"
-
-#, fuzzy
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Naam bijlage"
-
-#, fuzzy
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-#, fuzzy
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Gebruiker"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr ""
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr ""
-
-#, fuzzy
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Verzamelingen"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Verzamelingen"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr ""
-
-#, fuzzy
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Verzamelingen"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Verzamelingen"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr ""
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Verzameling"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr ""
-
-#, fuzzy
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Verzameling"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Verzamelingen"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/pt_BR.po b/trytond/webdav/locale/pt_BR.po
deleted file mode 100644
index 0160957..0000000
--- a/trytond/webdav/locale/pt_BR.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"Você não pode criar um anexo chamado \"%(attachment)s\" na coleção "
-"\"%(collection)s\" porque já existe uma coleção com este nome."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "O nome da coleção deve ser único dentro da coleção!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"Você não pode criar uma coleção chamada \"%(parent)s\" na coleção "
-"\"%(child)s\"  porque já existe um arquivo com este nome."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Caminho"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Compartilhamentos"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Filhos"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Nome completo"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Data de criação"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Criado por"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Domínio"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Modelo"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Nome"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Pai"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Nome"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Data de edição"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Editado por"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Data de criação"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Criado por"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Data de expiração"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Chave"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Nota"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Caminho"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Nome"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Usuário"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Data de edição"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Editado por"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Coleções"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Coleções"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Compartilhamentos"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Coleções"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Coleções"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Compartilhamentos"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Coleção"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Compartilhado"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr ""
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr ""
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr ""
diff --git a/trytond/webdav/locale/ru_RU.po b/trytond/webdav/locale/ru_RU.po
deleted file mode 100644
index 8cda1ed..0000000
--- a/trytond/webdav/locale/ru_RU.po
+++ /dev/null
@@ -1,185 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "Имя каталога должно быть уникальным внутри каталога!"
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"Вы не можете создать коллекцию \"%(parent)s\" в коллекции \"%(child)s\" так "
-"как существует файл с таким именем."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Путь"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Общие папки"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "Ссылка"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Подчиненый"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Полное название"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Дата создания"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Создано пользователем"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Область"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Модель"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Наименование"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Предок"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Наименование"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Дата изменения"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Изменено пользователем"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Дата создания"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Создано пользователем"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Дата окончания"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Ключ"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Комментарий"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Путь"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Наименование"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "Ссылка"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Пользователь"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Дата изменения"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Изменено пользователем"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Коллекции"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Коллекции"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Общие папки"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Коллекции"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Коллекции в виде дерева"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Общие папки"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Каталог"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Общая папка"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Каталог"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Коллекции"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Общая папка"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Общие папки"
diff --git a/trytond/webdav/locale/sl_SI.po b/trytond/webdav/locale/sl_SI.po
deleted file mode 100644
index ffa39d4..0000000
--- a/trytond/webdav/locale/sl_SI.po
+++ /dev/null
@@ -1,187 +0,0 @@
-# 
-msgid ""
-msgstr "Content-Type: text/plain; charset=utf-8\n"
-
-msgctxt "error:ir.attachment:"
-msgid ""
-"You can not create an attachment named \"%(attachment)s\" in collection "
-"\"%(collection)s\" because there is already a collection with that name."
-msgstr ""
-"Priloge \"%(attachment)s\" ni možno pripeti v zbirko \"%(collection)s\", ker"
-" že obstaja zbirka s tem imenom."
-
-msgctxt "error:webdav.collection:"
-msgid "The collection name must be unique inside a collection!"
-msgstr "Ime zbirke mora biti edinstveno znotraj zbirke."
-
-msgctxt "error:webdav.collection:"
-msgid ""
-"You can not create a collection named \"%(parent)s\" in collection "
-"\"%(child)s\" because there is already a file with that name."
-msgstr ""
-"Zbirke z imenom \"%(parent)s\" v zbirki \"%(child)s\" ni možno izdelati, ker"
-" že obstaja datoteka z istim imenom."
-
-msgctxt "field:ir.attachment,path:"
-msgid "Path"
-msgstr "Pot"
-
-msgctxt "field:ir.attachment,shares:"
-msgid "Shares"
-msgstr "Skupne rabe"
-
-msgctxt "field:ir.attachment,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.collection,childs:"
-msgid "Children"
-msgstr "Podzbirke"
-
-msgctxt "field:webdav.collection,complete_name:"
-msgid "Complete Name"
-msgstr "Polno ime"
-
-msgctxt "field:webdav.collection,create_date:"
-msgid "Create Date"
-msgstr "Izdelano"
-
-msgctxt "field:webdav.collection,create_uid:"
-msgid "Create User"
-msgstr "Izdelal"
-
-msgctxt "field:webdav.collection,domain:"
-msgid "Domain"
-msgstr "Domena"
-
-msgctxt "field:webdav.collection,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.collection,model:"
-msgid "Model"
-msgstr "Model"
-
-msgctxt "field:webdav.collection,name:"
-msgid "Name"
-msgstr "Naziv"
-
-msgctxt "field:webdav.collection,parent:"
-msgid "Parent"
-msgstr "Prednik"
-
-msgctxt "field:webdav.collection,rec_name:"
-msgid "Name"
-msgstr "Ime"
-
-msgctxt "field:webdav.collection,write_date:"
-msgid "Write Date"
-msgstr "Zapisano"
-
-msgctxt "field:webdav.collection,write_uid:"
-msgid "Write User"
-msgstr "Zapisal"
-
-msgctxt "field:webdav.share,create_date:"
-msgid "Create Date"
-msgstr "Izdelano"
-
-msgctxt "field:webdav.share,create_uid:"
-msgid "Create User"
-msgstr "Izdelal"
-
-msgctxt "field:webdav.share,expiration_date:"
-msgid "Expiration Date"
-msgstr "Datum veljavnosti"
-
-msgctxt "field:webdav.share,id:"
-msgid "ID"
-msgstr "ID"
-
-msgctxt "field:webdav.share,key:"
-msgid "Key"
-msgstr "Ključ"
-
-msgctxt "field:webdav.share,note:"
-msgid "Note"
-msgstr "Opomba"
-
-msgctxt "field:webdav.share,path:"
-msgid "Path"
-msgstr "Pot"
-
-msgctxt "field:webdav.share,rec_name:"
-msgid "Name"
-msgstr "Ime"
-
-msgctxt "field:webdav.share,url:"
-msgid "URL"
-msgstr "URL"
-
-msgctxt "field:webdav.share,user:"
-msgid "User"
-msgstr "Uporabnik"
-
-msgctxt "field:webdav.share,write_date:"
-msgid "Write Date"
-msgstr "Zapisano"
-
-msgctxt "field:webdav.share,write_uid:"
-msgid "Write User"
-msgstr "Zapisal"
-
-msgctxt "model:ir.action,name:act_collection_list"
-msgid "Collections"
-msgstr "Zbirke"
-
-msgctxt "model:ir.action,name:act_collection_tree"
-msgid "Collections"
-msgstr "Zbirke"
-
-msgctxt "model:ir.action,name:act_share_list"
-msgid "Shares"
-msgstr "Skupne rabe"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_list"
-msgid "Collections"
-msgstr "Zbirke"
-
-msgctxt "model:ir.ui.menu,name:menu_collection_tree"
-msgid "Collections"
-msgstr "Zbirke"
-
-msgctxt "model:ir.ui.menu,name:menu_share_list"
-msgid "Shares"
-msgstr "Skupne rabe"
-
-msgctxt "model:ir.ui.menu,name:menu_webdav"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "model:webdav.collection,name:"
-msgid "Collection"
-msgstr "Zbirka"
-
-msgctxt "model:webdav.share,name:"
-msgid "Share"
-msgstr "Skupna raba"
-
-msgctxt "view:ir.attachment:"
-msgid "WebDAV"
-msgstr "WebDAV"
-
-msgctxt "view:webdav.collection:"
-msgid "Collection"
-msgstr "Zbirka"
-
-msgctxt "view:webdav.collection:"
-msgid "Collections"
-msgstr "Zbirke"
-
-msgctxt "view:webdav.share:"
-msgid "Share"
-msgstr "Skupna raba"
-
-msgctxt "view:webdav.share:"
-msgid "Shares"
-msgstr "Skupne rabe"
diff --git a/trytond/webdav/tryton.cfg b/trytond/webdav/tryton.cfg
deleted file mode 100644
index 6912072..0000000
--- a/trytond/webdav/tryton.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-[tryton]
-depends:
-    ir
-    res
-xml:
-    webdav.xml
diff --git a/trytond/webdav/view/attachment_form.xml b/trytond/webdav/view/attachment_form.xml
deleted file mode 100644
index 73ee3ae..0000000
--- a/trytond/webdav/view/attachment_form.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<data>
-  <xpath expr="/form/notebook/page[@name='description']"
-      position="after">
-      <page string="WebDAV" id="webdav">
-          <label name="url"/>
-          <group id="url">
-              <field name="url"/>
-              <field name="url" widget="url"/>
-          </group>
-          <field name="shares" colspan="4"/>
-      </page>
-  </xpath>
-</data>
diff --git a/trytond/webdav/view/collection_form.xml b/trytond/webdav/view/collection_form.xml
deleted file mode 100644
index f0c12d8..0000000
--- a/trytond/webdav/view/collection_form.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<form string="Collection">
-    <label name="name"/>
-    <field name="name"/>
-    <label name="parent"/>
-    <field name="parent"/>
-    <label name="model"/>
-    <field name="model"/>
-    <label name="domain"/>
-    <field name="domain"/>
-    <field name="childs" colspan="4"/>
-</form>
diff --git a/trytond/webdav/view/collection_list.xml b/trytond/webdav/view/collection_list.xml
deleted file mode 100644
index d6d170f..0000000
--- a/trytond/webdav/view/collection_list.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<tree string="Collections">
-    <field name="name"/>
-    <field name="model"/>
-</tree>
diff --git a/trytond/webdav/view/collection_tree.xml b/trytond/webdav/view/collection_tree.xml
deleted file mode 100644
index 5cc3702..0000000
--- a/trytond/webdav/view/collection_tree.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<tree string="Collections">
-    <field name="name"/>
-    <field name="model"/>
-    <field name="parent" tree_invisible="1"/>
-    <field name="childs" tree_invisible="1"/>
-</tree>
diff --git a/trytond/webdav/view/share_form.xml b/trytond/webdav/view/share_form.xml
deleted file mode 100644
index a1a19de..0000000
--- a/trytond/webdav/view/share_form.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<form string="Share">
-    <label name="path"/>
-    <field name="path"/>
-    <label name="key"/>
-    <field name="key"/>
-    <label name="user"/>
-    <field name="user"/>
-    <label name="expiration_date"/>
-    <field name="expiration_date"/>
-    <label name="url"/>
-    <group id="url" colspan="2">
-        <field name="url"/>
-        <field name="url" widget="url"/>
-    </group>
-    <notebook>
-        <page name="note">
-            <field name="note" colspan="4"/>
-        </page>
-    </notebook>
-</form>
diff --git a/trytond/webdav/view/share_list.xml b/trytond/webdav/view/share_list.xml
deleted file mode 100644
index 5502df7..0000000
--- a/trytond/webdav/view/share_list.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<tree string="Shares">
-    <field name="path"/>
-    <field name="user"/>
-    <field name="expiration_date"/>
-</tree>
diff --git a/trytond/webdav/webdav.py b/trytond/webdav/webdav.py
deleted file mode 100644
index d79d6df..0000000
--- a/trytond/webdav/webdav.py
+++ /dev/null
@@ -1,832 +0,0 @@
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import os
-import time
-import urllib
-import urlparse
-import socket
-import encodings
-import uuid
-import datetime
-from ast import literal_eval
-
-from dateutil.relativedelta import relativedelta
-from sql.functions import Extract
-from sql.conditionals import Coalesce
-
-from trytond.model import ModelView, ModelSQL, fields, Unique
-from trytond.tools import reduce_ids
-from trytond.transaction import Transaction
-from trytond.pool import Pool
-from trytond.config import config
-from trytond.pyson import Eval
-from trytond.tools import grouped_slice
-
-__all__ = [
-    'Collection', 'Share', 'Attachment',
-    ]
-
-
-def get_webdav_url():
-    if config.get('ssl', 'privatekey'):
-        protocol = 'https'
-    else:
-        protocol = 'http'
-    hostname = (config.get('webdav', 'hostname')
-        or unicode(socket.getfqdn(), 'utf8'))
-    hostname = '.'.join(encodings.idna.ToASCII(part) for part in
-        hostname.split('.'))
-    return urlparse.urlunsplit((protocol, hostname,
-        urllib.quote(
-            Transaction().cursor.database_name.encode('utf-8') + '/'),
-            None, None))
-
-
-class Collection(ModelSQL, ModelView):
-    "Collection"
-    __name__ = "webdav.collection"
-    name = fields.Char('Name', required=True, select=True)
-    parent = fields.Many2One('webdav.collection', 'Parent',
-       ondelete='RESTRICT', domain=[('model', '=', None)])
-    childs = fields.One2Many('webdav.collection', 'parent', 'Children')
-    model = fields.Many2One('ir.model', 'Model')
-    domain = fields.Char('Domain')
-    complete_name = fields.Function(fields.Char('Complete Name'),
-        'get_rec_name')
-
-    @classmethod
-    def __setup__(cls):
-        super(Collection, cls).__setup__()
-        table = cls.__table__()
-        cls._sql_constraints += [
-            ('name_parent_uniq', Unique(table, table.name, table.parent),
-                'The collection name must be unique inside a collection!'),
-        ]
-        cls._error_messages.update({
-                'collection_file_name': ('You can not create a collection '
-                    'named "%(parent)s" in collection "%(child)s" because '
-                    'there is already a file with that name.'),
-                })
-        cls.ext2mime = {
-            '.png': 'image/png',
-            '.odt': 'application/vnd.oasis.opendocument.text',
-            '.pdf': 'application/pdf',
-        }
-
-    @classmethod
-    def order_complete_name(cls, tables):
-        return cls.name.convert_order('name', tables, cls)
-
-    @staticmethod
-    def default_domain():
-        return '[]'
-
-    def get_rec_name(self, name):
-        if self.parent:
-            return self.parent.rec_name + '/' + self.name
-        else:
-            return self.name
-
-    @classmethod
-    def validate(cls, collections):
-        super(Collection, cls).validate(collections)
-        cls.check_recursion(collections, rec_name='name')
-        cls.check_attachment(collections)
-
-    @classmethod
-    def check_attachment(cls, collections):
-        pool = Pool()
-        Attachment = pool.get('ir.attachment')
-        for collection in collections:
-            if collection.parent:
-                attachments = Attachment.search([
-                    ('resource', '=', '%s,%s' %
-                        (cls.__name__, collection.parent.id)),
-                    ])
-                for attachment in attachments:
-                    if attachment.name == collection.name:
-                        cls.raise_user_error('collection_file_name', {
-                                'parent': collection.parent.rec_name,
-                                'child': collection.rec_name,
-                                })
-
-    @classmethod
-    def _uri2object(cls, uri, object_name=__name__, object_id=None,
-            cache=None):
-        pool = Pool()
-        Attachment = pool.get('ir.attachment')
-        Report = pool.get('ir.action.report')
-        cache_uri = uri
-
-        if cache is not None:
-            cache.setdefault('_uri2object', {})
-            if cache_uri in cache['_uri2object']:
-                return cache['_uri2object'][cache_uri]
-
-        if not uri:
-            if cache is not None:
-                cache['_uri2object'][cache_uri] = (cls.__name__, None)
-            return cls.__name__, None
-        name, uri = (uri.split('/', 1) + [None])[0:2]
-        if object_name == cls.__name__:
-            collection_ids = None
-            if cache is not None:
-                cache.setdefault('_parent2collection_ids', {})
-                if object_id in cache['_parent2collection_ids']:
-                    collection_ids = cache['_parent2collection_ids'][
-                        object_id].get(name, [])
-            if collection_ids is None:
-                collections = cls.search([
-                    ('parent', '=', object_id),
-                    ])
-                collection_ids = []
-                if cache is not None:
-                    cache['_parent2collection_ids'].setdefault(object_id, {})
-                for collection in collections:
-                    if cache is not None:
-                        cache['_parent2collection_ids'][object_id]\
-                            .setdefault(collection.name, [])
-                        cache['_parent2collection_ids'][object_id][
-                            collection.name].append(collection.id)
-                        cache.setdefault('_collection_name', {})
-                        if collection.model and uri:
-                            cache['_collection_name'][collection.id] = \
-                                collection.model.model
-                        else:
-                            cache['_collection_name'][collection.id] = \
-                                cls.__name__
-                    if collection.name == name:
-                        collection_ids.append(collection.id)
-            if collection_ids:
-                object_id = collection_ids[0]
-                object_name2 = None
-                if cache is not None:
-                    cache.setdefault('_collection_name', {})
-                    if object_id in cache['_collection_name']:
-                        object_name2 = cache['_collection_name'][object_id]
-                if object_name2 is None:
-                    collection = cls(object_id)
-                    if collection.model and uri:
-                        object_name = collection.model.model
-                        if cache is not None:
-                            cache['_collection_name'][object_id] = object_name
-                else:
-                    object_name = object_name2
-            else:
-                if uri:
-                    if cache is not None:
-                        cache['_uri2object'][cache_uri] = (None, 0)
-                    return None, 0
-
-                attachment_ids = None
-                if cache is not None:
-                    cache.setdefault('_model&id2attachment_ids', {})
-                    if (object_name, object_id) in \
-                            cache['_model&id2attachment_ids']:
-                        attachment_ids = cache['_model&id2attachment_ids'][
-                            (object_name, object_id)].get(name, [])
-                attachment_id = None
-                if attachment_ids is None:
-                    attachments = Attachment.search([
-                        ('resource', '=', '%s,%s' % (object_name, object_id)),
-                        ])
-                    key = (object_name, object_id)
-                    attachment_ids = []
-                    if cache is not None:
-                        cache['_model&id2attachment_ids'].setdefault(key, {})
-                    for attachment in attachments:
-                        if cache is not None:
-                            cache.setdefault('_model&id&name2attachment_ids',
-                                    {})
-                            cache['_model&id&name2attachment_ids'].setdefault(
-                                    key, {})
-                            cache['_model&id&name2attachment_ids'][key]\
-                                .setdefault(attachment.name, [])
-                            cache['_model&id&name2attachment_ids'][key][
-                                attachment.name].append(attachment.id)
-                        if attachment.name == name:
-                            attachment_id = attachment.id
-                else:
-                    key = (object_name, object_id)
-                    cache.setdefault('_model&id&name2attachment_ids', {})
-                    cache['_model&id&name2attachment_ids'].setdefault(key, {})
-                    attachment_id = cache['_model&id&name2attachment_ids'][
-                        key].get(name, [None])[0]
-                if attachment_id:
-                    object_name = 'ir.attachment'
-                    object_id = attachment_id
-                else:
-                    object_name = None
-                    object_id = None
-        else:
-            splitted_name = name.rsplit('-', 1)
-            if len(splitted_name) != 2:
-                if cache is not None:
-                    cache['_uri2object'][cache_uri] = (object_name, 0)
-                return object_name, 0
-            object_id = int(splitted_name[1].strip())
-            if uri:
-                if '/' in uri:
-                    if cache is not None:
-                        cache['_uri2object'][cache_uri] = (None, 0)
-                    return None, 0
-                reports = Report.search([
-                    ('model', '=', object_name),
-                    ])
-                for report in reports:
-                    report_name = (report.name + '-' + str(report.id)
-                        + '.' + report.extension)
-                    if uri == report_name:
-                        if cache is not None:
-                            cache['_uri2object'][cache_uri] = \
-                                ('ir.action.report', object_id)
-                        return 'ir.action.report', object_id
-                name = uri
-                attachment_ids = None
-                if cache is not None:
-                    cache.setdefault('_model&id2attachment_ids', {})
-                    if (object_name, object_id) in \
-                            cache['_model&id2attachment_ids']:
-                        attachment_ids = cache['_model&id2attachment_ids'][
-                            (object_name, object_id)].get(name, [])
-                if attachment_ids is None:
-                    attachments = Attachment.search([
-                        ('resource', '=', '%s,%s' % (object_name, object_id)),
-                        ])
-                    key = (object_name, object_id)
-                    attachment_ids = []
-                    if cache is not None:
-                        cache['_model&id2attachment_ids'].setdefault(key, {})
-                    for attachment in attachments:
-                        if cache is not None:
-                            cache['_model&id2attachment_ids'][key]\
-                                .setdefault(attachment.name, [])
-                            cache['_model&id2attachment_ids'][key][
-                                attachment.name].append(attachment.id)
-                        if attachment.name == name:
-                            attachment_ids.append(attachment.id)
-                if attachment_ids:
-                    object_name = 'ir.attachment'
-                    object_id = attachment_ids[0]
-                else:
-                    object_name = None
-                    object_id = None
-                if cache is not None:
-                    cache['_uri2object'][cache_uri] = (object_name, object_id)
-                return object_name, object_id
-        if uri:
-            res = cls._uri2object(uri, object_name, object_id, cache=cache)
-            if cache is not None:
-                cache['_uri2object'][cache_uri] = res
-            return res
-        if cache is not None:
-            cache['_uri2object'][cache_uri] = (object_name, object_id)
-        return object_name, object_id
-
-    @classmethod
-    def get_childs(cls, uri, filter=None, cache=None):
-        pool = Pool()
-        Report = pool.get('ir.action.report')
-        res = []
-        if filter:
-            return []
-        if not uri:
-            collections = cls.search([
-                ('parent', '=', None),
-                ])
-            for collection in collections:
-                if '/' in collection.name:
-                    continue
-                res.append(collection.name)
-                if cache is not None:
-                    cache.setdefault(cls.__name__, {})
-                    cache[cls.__name__][collection.id] = {}
-            return res
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name == cls.__name__ and object_id:
-            collection = cls(object_id)
-            if collection.model:
-                Model = pool.get(collection.model.model)
-                if not Model:
-                    return res
-                models = Model.search(
-                    literal_eval(collection.domain))
-                for child in models:
-                    if '/' in child.rec_name:
-                        continue
-                    res.append(child.rec_name + '-' + str(child.id))
-                    if cache is not None:
-                        cache.setdefault(Model.__name__, {})
-                        cache[Model.__name__][child.id] = {}
-                return res
-            else:
-                for child in collection.childs:
-                    if '/' in child.name:
-                        continue
-                    res.append(child.name)
-                    if cache is not None:
-                        cache.setdefault(cls.__name__, {})
-                        cache[cls.__name__][child.id] = {}
-        if object_name not in ('ir.attachment', 'ir.action.report'):
-            reports = Report.search([
-                ('model', '=', object_name),
-                ])
-            for report in reports:
-                report_name = (report.name + '-' + str(report.id)
-                    + '.' + report.extension)
-                if '/' in report_name:
-                    continue
-                res.append(report_name)
-                if cache is not None:
-                    cache.setdefault(Report.__name__, {})
-                    cache[Report.__name__][report.id] = {}
-
-            Attachment = pool.get('ir.attachment')
-            attachments = Attachment.search([
-                    ('resource', '=', '%s,%s' % (object_name, object_id)),
-                    ])
-            for attachment in attachments:
-                if attachment.name and not attachment.link:
-                    if '/' in attachment.name:
-                        continue
-                    res.append(attachment.name)
-                    if cache is not None:
-                        cache.setdefault(Attachment.__name__, {})
-                        cache[Attachment.__name__][attachment.id] = {}
-        return res
-
-    @classmethod
-    def get_resourcetype(cls, uri, cache=None):
-        from pywebdav.lib.constants import COLLECTION, OBJECT
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name in ('ir.attachment', 'ir.action.report'):
-            return OBJECT
-        return COLLECTION
-
-    @classmethod
-    def get_displayname(cls, uri, cache=None):
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        Model = Pool().get(object_name)
-        return Model(object_id).rec_name
-
-    @classmethod
-    def get_contentlength(cls, uri, cache=None):
-        pool = Pool()
-        Attachment = pool.get('ir.attachment')
-
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name == 'ir.attachment':
-
-            if cache is not None:
-                cache.setdefault('ir.attachment', {})
-                ids = cache['ir.attachment'].keys()
-                if object_id not in ids:
-                    ids.append(object_id)
-                elif 'contentlength' in cache['ir.attachment'][object_id]:
-                    return cache['ir.attachment'][object_id]['contentlength']
-            else:
-                ids = [object_id]
-
-            attachments = Attachment.browse(ids)
-
-            res = '0'
-            for attachment in attachments:
-                size = '0'
-                try:
-                    if attachment.data_size:
-                        size = str(attachment.data_size)
-                except Exception:
-                    pass
-                if attachment.id == object_id:
-                    res = size
-                if cache is not None:
-                    cache['ir.attachment'].setdefault(attachment.id, {})
-                    cache['ir.attachment'][attachment.id]['contentlength'] = \
-                        size
-            return res
-        return '0'
-
-    @classmethod
-    def get_contenttype(cls, uri, cache=None):
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name in ('ir.attachment', 'ir.action.report'):
-            ext = os.path.splitext(uri)[1]
-            if not ext:
-                return "application/octet-stream"
-            return cls.ext2mime.get(ext, 'application/octet-stream')
-        return "application/octet-stream"
-
-    @classmethod
-    def get_creationdate(cls, uri, cache=None):
-        pool = Pool()
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name == 'ir.attachment':
-            Model = pool.get(object_name)
-            if object_id:
-                if cache is not None:
-                    cache.setdefault(Model.__name__, {})
-                    ids = cache[Model.__name__].keys()
-                    if object_id not in ids:
-                        ids.append(object_id)
-                    elif 'creationdate' in cache[Model.__name__][object_id]:
-                        return cache[Model.__name__][object_id][
-                            'creationdate']
-                else:
-                    ids = [object_id]
-                res = None
-                cursor = Transaction().cursor
-                table = Model.__table__()
-                for sub_ids in grouped_slice(ids):
-                    red_sql = reduce_ids(table.id, sub_ids)
-                    cursor.execute(*table.select(table.id,
-                            Extract('EPOCH', table.create_date),
-                            where=red_sql))
-                    for object_id2, date in cursor.fetchall():
-                        if object_id2 == object_id:
-                            res = date
-                        if cache is not None:
-                            cache[Model.__name__].setdefault(object_id2, {})
-                            cache[Model.__name__][object_id2][
-                                'creationdate'] = date
-                if res is not None:
-                    return res
-        return time.time()
-
-    @classmethod
-    def get_lastmodified(cls, uri, cache=None):
-        pool = Pool()
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name == 'ir.attachment':
-            Model = pool.get(object_name)
-            if object_id:
-                if cache is not None:
-                    cache.setdefault(Model.__name__, {})
-                    ids = cache[Model.__name__].keys()
-                    if object_id not in ids:
-                        ids.append(object_id)
-                    elif 'lastmodified' in cache[Model.__name__][object_id]:
-                        return cache[Model.__name__][object_id][
-                            'lastmodified']
-                else:
-                    ids = [object_id]
-                res = None
-                cursor = Transaction().cursor
-                table = Model.__table__()
-                for sub_ids in grouped_slice(ids):
-                    red_sql = reduce_ids(table.id, sub_ids)
-                    cursor.execute(*table.select(table.id,
-                            Extract('EPOCH',
-                                Coalesce(table.write_date, table.create_date)),
-                            where=red_sql))
-                    for object_id2, date in cursor.fetchall():
-                        if object_id2 == object_id:
-                            res = date
-                        if cache is not None:
-                            cache[Model.__name__].setdefault(object_id2, {})
-                            cache[Model.__name__][object_id2][
-                                'lastmodified'] = date
-                if res is not None:
-                    return res
-        return time.time()
-
-    @classmethod
-    def get_data(cls, uri, cache=None):
-        from pywebdav.lib.errors import DAV_NotFound
-        pool = Pool()
-        Attachment = pool.get('ir.attachment')
-        Report = pool.get('ir.action.report')
-
-        if uri:
-            object_name, object_id = cls._uri2object(uri, cache=cache)
-
-            if object_name == 'ir.attachment' and object_id:
-                if cache is not None:
-                    cache.setdefault('ir.attachment', {})
-                    ids = cache['ir.attachment'].keys()
-                    if object_id not in ids:
-                        ids.append(object_id)
-                    elif 'data' in cache['ir.attachment'][object_id]:
-                        res = cache['ir.attachment'][object_id]['data']
-                        if res == DAV_NotFound:
-                            raise DAV_NotFound
-                        return res
-                else:
-                    ids = [object_id]
-                attachments = Attachment.browse(ids)
-
-                res = DAV_NotFound
-                for attachment in attachments:
-                    data = DAV_NotFound
-                    try:
-                        if attachment.data is not None:
-                            data = str(attachment.data)
-                    except Exception:
-                        pass
-                    if attachment.id == object_id:
-                        res = data
-                    if cache is not None:
-                        cache['ir.attachment'].setdefault(attachment.id, {})
-                        cache['ir.attachment'][attachment.id]['data'] = data
-                if res == DAV_NotFound:
-                    raise DAV_NotFound
-                return res
-
-            if object_name == 'ir.action.report' and object_id:
-                report_id = int(uri.rsplit('/', 1)[-1].rsplit('-',
-                    1)[-1].rsplit('.', 1)[0])
-                report = Report(report_id)
-                if report.report_name:
-                    Report = pool.get(report.report_name,
-                            type='report')
-                    val = Report.execute([object_id],
-                        {'id': object_id, 'ids': [object_id]})
-                    return val[1]
-        raise DAV_NotFound
-
-    @classmethod
-    def put(cls, uri, data, content_type, cache=None):
-        from pywebdav.lib.errors import DAV_Forbidden
-        from pywebdav.lib.utils import get_uriparentpath, get_urifilename
-        object_name, object_id = cls._uri2object(get_uriparentpath(uri),
-                cache=cache)
-        if not object_name \
-                or object_name == 'ir.attachment' \
-                or not object_id:
-            raise DAV_Forbidden
-        pool = Pool()
-        Attachment = pool.get('ir.attachment')
-        object_name2, object_id2 = cls._uri2object(uri, cache=cache)
-        if not object_id2:
-            name = get_urifilename(uri)
-            try:
-                Attachment.create([{
-                            'name': name,
-                            'data': data,
-                            'resource': '%s,%s' % (object_name, object_id),
-                            }])
-            except Exception:
-                raise DAV_Forbidden
-        else:
-            try:
-                Attachment.write(object_id2, {
-                    'data': data,
-                    })
-            except Exception:
-                raise DAV_Forbidden
-        return
-
-    @classmethod
-    def mkcol(cls, uri, cache=None):
-        from pywebdav.lib.errors import DAV_Forbidden
-        from pywebdav.lib.utils import get_uriparentpath, get_urifilename
-        if uri[-1:] == '/':
-            uri = uri[:-1]
-        object_name, object_id = cls._uri2object(get_uriparentpath(uri),
-                cache=cache)
-        if object_name != 'webdav.collection':
-            raise DAV_Forbidden
-        name = get_urifilename(uri)
-        try:
-            cls.create([{
-                        'name': name,
-                        'parent': object_id,
-                        }])
-        except Exception:
-            raise DAV_Forbidden
-        return 201
-
-    @classmethod
-    def rmcol(cls, uri, cache=None):
-        from pywebdav.lib.errors import DAV_Forbidden
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name != 'webdav.collection' \
-                or not object_id:
-            raise DAV_Forbidden
-        try:
-            cls.delete([cls(object_id)])
-        except Exception:
-            raise DAV_Forbidden
-        return 200
-
-    @classmethod
-    def rm(cls, uri, cache=None):
-        from pywebdav.lib.errors import DAV_Forbidden
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if not object_name:
-            raise DAV_Forbidden
-        if object_name != 'ir.attachment' \
-                or not object_id:
-            raise DAV_Forbidden
-        pool = Pool()
-        Model = pool.get(object_name)
-        try:
-            Model.delete([Model(object_id)])
-        except Exception:
-            raise DAV_Forbidden
-        return 200
-
-    @classmethod
-    def exists(cls, uri, cache=None):
-        object_name, object_id = cls._uri2object(uri, cache=cache)
-        if object_name and object_id:
-            return 1
-        return None
-
-    @staticmethod
-    def current_user_privilege_set(uri, cache=None):
-        return ['create', 'read', 'write', 'delete']
-
-
-class Share(ModelSQL, ModelView):
-    "Share"
-    __name__ = 'webdav.share'
-    _rec_name = 'key'
-
-    path = fields.Char('Path', required=True, select=True)
-    key = fields.Char('Key', required=True, select=True,
-        states={
-            'readonly': True,
-            })
-    user = fields.Many2One('res.user', 'User', required=True)
-    expiration_date = fields.Date('Expiration Date', required=True)
-    note = fields.Text('Note')
-    url = fields.Function(fields.Char('URL'), 'get_url')
-
-    @staticmethod
-    def default_key():
-        return uuid.uuid4().hex
-
-    @staticmethod
-    def default_user():
-        return Transaction().user
-
-    @staticmethod
-    def default_expiration_date():
-        return datetime.date.today() + relativedelta(months=1)
-
-    def get_url(self, name):
-        return urlparse.urljoin(get_webdav_url(),
-            urlparse.urlunsplit((None, None,
-                    urllib.quote(self.path.encode('utf-8')),
-                    urllib.urlencode([('key', self.key)]), None)))
-
-    @staticmethod
-    def match(share, command, path):
-        "Test if share match with command and path"
-        today = datetime.date.today()
-        return (path.startswith(share.path)
-            and share.expiration_date > today
-            and command == 'GET')
-
-    @classmethod
-    def get_login(cls, key, command, path):
-        """Validate the key for the command and path
-        Return the user id if succeed or None
-        """
-        shares = cls.search([
-                ('key', '=', key),
-                ])
-        if not shares:
-            return None
-        for share in shares:
-            if cls.match(share, command, path):
-                return share.user.id
-        return None
-
-
-class Attachment(ModelSQL, ModelView):
-    __name__ = 'ir.attachment'
-
-    path = fields.Function(fields.Char('Path'), 'get_path')
-    url = fields.Function(fields.Char('URL'), 'get_url')
-    shares = fields.Function(fields.One2Many('webdav.share', None, 'Shares',
-            domain=[
-                ('path', '=', Eval('path')),
-                ],
-            depends=['path']), 'get_shares', 'set_shares')
-
-    @classmethod
-    def __setup__(cls):
-        super(Attachment, cls).__setup__()
-        cls._error_messages.update({
-                'collection_attachment_name': ('You can not create an '
-                    'attachment named "%(attachment)s" in collection '
-                    '"%(collection)s" because there is already a collection '
-                    'with that name.')
-                })
-
-    @classmethod
-    def validate(cls, attachments):
-        super(Attachment, cls).validate(attachments)
-        cls.check_collection(attachments)
-
-    @classmethod
-    def check_collection(cls, attachments):
-        pool = Pool()
-        Collection = pool.get('webdav.collection')
-        for attachment in attachments:
-            if attachment.resource:
-                model_name = attachment.resource.__name__
-                record_id = attachment.resource.id
-                if model_name == 'webdav.collection':
-                    collection = Collection(int(record_id))
-                    for child in collection.childs:
-                        if child.name == attachment.name:
-                            cls.raise_user_error(
-                                'collection_attachment_name', {
-                                    'attachment': attachment.rec_name,
-                                    'collection': collection.rec_name,
-                                    })
-
-    @classmethod
-    def get_path(cls, attachments, name):
-        pool = Pool()
-        Collection = pool.get('webdav.collection')
-        paths = dict((a.id, None) for a in attachments)
-
-        resources = {}
-        resource2attachments = {}
-        for attachment in attachments:
-            if not attachment.resource:
-                paths[attachment.id] = None
-                continue
-            model_name = attachment.resource.__name__
-            record_id = attachment.resource.id
-            resources.setdefault(model_name, set()).add(record_id)
-            resource2attachments.setdefault((model_name, record_id),
-                []).append(attachment)
-        collections = Collection.search([
-                ('model.model', 'in', resources.keys()),
-                ])
-        for collection in collections:
-            model_name = collection.model.model
-            Model = pool.get(model_name)
-            ids = list(resources[model_name])
-            domain = literal_eval(collection.domain)
-            domain = [domain, ('id', 'in', ids)]
-            records = Model.search(domain)
-            for record in records:
-                for attachment in resource2attachments[
-                        (model_name, record.id)]:
-                    paths[attachment.id] = '/'.join((collection.rec_name,
-                            record.rec_name + '-' + str(record.id),
-                            attachment.name))
-        if 'webdav.collection' in resources:
-            collection_ids = list(resources['webdav.collection'])
-            for collection in Collection.browse(collection_ids):
-                for attachment in resource2attachments[
-                        ('webdav.collection', collection.id)]:
-                    paths[attachment.id] = '/'.join((collection.rec_name,
-                            attachment.name))
-        return paths
-
-    def get_url(self, name):
-        if self.path:
-            return urlparse.urljoin(get_webdav_url(),
-                urllib.quote(self.path.encode('utf-8')))
-
-    @classmethod
-    def get_shares(cls, attachments, name):
-        Share = Pool().get('webdav.share')
-        result = dict((a.id, []) for a in attachments)
-        path2attachement = dict((a.path, a) for a in attachments)
-        shares = Share.search([
-                ('path', 'in', path2attachement.keys()),
-                ])
-        for share in shares:
-            attachment = path2attachement[share.path]
-            result[attachment.id].append(share.id)
-        return result
-
-    @classmethod
-    def set_shares(cls, attachments, name, values):
-        Share = Pool().get('webdav.share')
-
-        if not values:
-            return
-
-        def create(vlist):
-            to_create = []
-            for attachment in attachments:
-                for values in vlist:
-                    values = values.copy()
-                    values['path'] = attachment.path
-                    to_create.append(values)
-            if to_create:
-                Share.create(to_create)
-
-        def write(ids, values):
-            Share.write(Share.browse(ids), values)
-
-        def delete(share_ids):
-            Share.delete(Share.browse(share_ids))
-
-        actions = {
-            'create': create,
-            'write': write,
-            'delete': delete,
-            }
-        for value in values:
-            action = value[0]
-            args = value[1:]
-            actions[action](*args)
diff --git a/trytond/webdav/webdav.xml b/trytond/webdav/webdav.xml
deleted file mode 100644
index 5345da9..0000000
--- a/trytond/webdav/webdav.xml
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0"?>
-<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
-this repository contains the full copyright notices and license terms. -->
-<tryton>
-    <data>
-        <menuitem name="WebDAV" id="menu_webdav"
-            parent="ir.menu_administration"/>
-        <record model="ir.ui.menu-res.group" id="menu_webdav_group_admin">
-            <field name="menu" ref="menu_webdav"/>
-            <field name="group" ref="res.group_admin"/>
-        </record>
-
-        <record model="ir.ui.view" id="collection_view_tree">
-            <field name="model">webdav.collection</field>
-            <field name="type">tree</field>
-            <field name="field_childs">childs</field>
-            <field name="name">collection_tree</field>
-        </record>
-
-        <record model="ir.ui.view" id="collection_view_list">
-            <field name="model">webdav.collection</field>
-            <field name="type">tree</field>
-            <field name="name">collection_list</field>
-        </record>
-
-        <record model="ir.ui.view" id="collection_view_form">
-            <field name="model">webdav.collection</field>
-            <field name="type">form</field>
-            <field name="name">collection_form</field>
-        </record>
-        <record model="ir.action.act_window" id="act_collection_tree">
-            <field name="name">Collections</field>
-            <field name="type">ir.action.act_window</field>
-            <field name="res_model">webdav.collection</field>
-            <field name="domain" eval="[('parent', '=', None)]" pyson="1"/>
-        </record>
-        <record model="ir.action.act_window.view"
-            id="act_collection_tree_view1">
-            <field name="sequence" eval="10"/>
-            <field name="view" ref="collection_view_tree"/>
-            <field name="act_window" ref="act_collection_tree"/>
-        </record>
-        <record model="ir.action.act_window.view"
-            id="act_collection_tree_view2">
-            <field name="sequence" eval="20"/>
-            <field name="view" ref="collection_view_form"/>
-            <field name="act_window" ref="act_collection_tree"/>
-        </record>
-        <menuitem parent="menu_webdav"
-            action="act_collection_tree" id="menu_collection_tree"/>
-        <record model="ir.ui.menu-res.group" id="menu_collection_tree_group_admin">
-            <field name="menu" ref="menu_collection_tree"/>
-            <field name="group" ref="res.group_admin"/>
-        </record>
-
-        <record model="ir.action.act_window" id="act_collection_list">
-            <field name="name">Collections</field>
-            <field name="res_model">webdav.collection</field>
-        </record>
-        <record model="ir.action.act_window.view"
-            id="act_collection_list_view1">
-            <field name="sequence" eval="10"/>
-            <field name="view" ref="collection_view_list"/>
-            <field name="act_window" ref="act_collection_list"/>
-        </record>
-        <record model="ir.action.act_window.view"
-            id="act_collection_lis_view2">
-            <field name="sequence" eval="20"/>
-            <field name="view" ref="collection_view_form"/>
-            <field name="act_window" ref="act_collection_list"/>
-        </record>
-        <menuitem name="Collections" parent="menu_collection_tree"
-            action="act_collection_list" id="menu_collection_list"/>
-        <record model="ir.ui.menu-res.group" id="menu_collection_list_group_admin">
-            <field name="menu" ref="menu_collection_list"/>
-            <field name="group" ref="res.group_admin"/>
-        </record>
-
-        <record model="ir.ui.view" id="share_view_list">
-            <field name="model">webdav.share</field>
-            <field name="type">tree</field>
-            <field name="name">share_list</field>
-        </record>
-
-        <record model="ir.ui.view" id="share_view_form">
-            <field name="model">webdav.share</field>
-            <field name="type">form</field>
-            <field name="name">share_form</field>
-        </record>
-
-        <record model="ir.action.act_window" id="act_share_list">
-            <field name="name">Shares</field>
-            <field name="type">ir.action.act_window</field>
-            <field name="res_model">webdav.share</field>
-        </record>
-        <record model="ir.action.act_window.view" id="act_share_list_view1">
-            <field name="sequence" eval="10"/>
-            <field name="view" ref="share_view_list"/>
-            <field name="act_window" ref="act_share_list"/>
-        </record>
-        <record model="ir.action.act_window.view" id="act_share_list_view2">
-            <field name="sequence" eval="20"/>
-            <field name="view" ref="share_view_form"/>
-            <field name="act_window" ref="act_share_list"/>
-        </record>
-        <menuitem parent="menu_webdav" action="act_share_list"
-            id="menu_share_list"/>
-
-        <record model="ir.rule.group" id="rule_group_share">
-            <field name="model" search="[('model', '=', 'webdav.share')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="True"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule" id="rule_share">
-            <field name="domain"
-                eval="[('user', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_share"/>
-        </record>
-
-        <record model="ir.rule.group" id="rule_group_share_admin">
-            <field name="model" search="[('model', '=', 'webdav.share')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="False"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule.group-res.group"
-            id="rule_group_share_admin_group_admin">
-            <field name="rule_group" ref="rule_group_share_admin"/>
-            <field name="group" ref="res.group_admin"/>
-        </record>
-
-        <record model="ir.ui.view" id="attachment_view_form">
-            <field name="model">ir.attachment</field>
-            <field name="type">form</field>
-            <field name="inherit" ref="ir.attachment_view_form"/>
-            <field name="name">attachment_form</field>
-        </record>
-    </data>
-</tryton>
diff --git a/trytond/wizard/wizard.py b/trytond/wizard/wizard.py
index 4aa0df3..fda671a 100644
--- a/trytond/wizard/wizard.py
+++ b/trytond/wizard/wizard.py
@@ -314,8 +314,7 @@ class Wizard(WarningErrorMixin, URLMixin, PoolBase):
         Session = pool.get('ir.session.wizard')
         self._session_id = session_id
         session = Session(session_id)
-        data = json.loads(session.data.encode('utf-8'),
-            object_hook=JSONDecoder())
+        data = json.loads(session.data, object_hook=JSONDecoder())
         for state_name, state in self.states.iteritems():
             if isinstance(state, StateView):
                 Target = pool.get(state.model_name)
diff --git a/trytond/wsgi.py b/trytond/wsgi.py
new file mode 100644
index 0000000..30deb51
--- /dev/null
+++ b/trytond/wsgi.py
@@ -0,0 +1,86 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import logging
+
+from werkzeug.wrappers import Response
+from werkzeug.routing import Map, Rule
+from werkzeug.exceptions import abort
+
+import wrapt
+
+from trytond.protocols.wrappers import Request
+from trytond.protocols.jsonrpc import JSONProtocol
+from trytond.protocols.xmlrpc import XMLProtocol
+
+__all__ = ['TrytondWSGI', 'app']
+
+logger = logging.getLogger(__name__)
+
+
+class TrytondWSGI(object):
+
+    def __init__(self):
+        self.url_map = Map([])
+        self.protocols = [JSONProtocol, XMLProtocol]
+        self.error_handlers = []
+
+    def route(self, string, methods=None):
+        def decorator(func):
+            self.url_map.add(Rule(string, endpoint=func, methods=methods))
+            return func
+        return decorator
+
+    @wrapt.decorator
+    def auth_required(self, wrapped, instance, args, kwargs):
+        request = args[0]
+        if request.user_id:
+            return wrapped(*args, **kwargs)
+        else:
+            abort(303)
+
+    def dispatch_request(self, request):
+        adapter = self.url_map.bind_to_environ(request.environ)
+        try:
+            endpoint, request.view_args = adapter.match()
+            return endpoint(request, **request.view_args)
+        except Exception, e:
+            response = e
+            for error_handler in self.error_handlers:
+                rv = error_handler(e)
+                if isinstance(rv, Response):
+                    response = rv
+            return response
+
+    def wsgi_app(self, environ, start_response):
+        for cls in self.protocols:
+            if cls.content_type in environ.get('CONTENT_TYPE', ''):
+                request = cls.request(environ)
+                break
+        else:
+            request = Request(environ)
+        data = self.dispatch_request(request)
+        if not isinstance(data, Response):
+            for cls in self.protocols:
+                for mimetype in request.accept_mimetypes:
+                    if cls.content_type in mimetype:
+                        response = cls.response(data, request)
+                        break
+                else:
+                    continue
+                break
+            else:
+                for cls in self.protocols:
+                    if cls.content_type in environ.get('CONTENT_TYPE', ''):
+                        response = cls.response(data, request)
+                        break
+                else:
+                    response = Response(data)
+        else:
+            response = data
+        # TODO custom process response
+        return response(environ, start_response)
+
+    def __call__(self, environ, start_response):
+        return self.wsgi_app(environ, start_response)
+
+app = TrytondWSGI()
-- 
tryton-server



More information about the tryton-debian-vcs mailing list