diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
index cdf686b42b02df70752ae3f5f07769c522328483..715941ce02fb9d5041cddd913cc19a980a54c4e2 100644
--- a/addons/account/models/account_bank_statement.py
+++ b/addons/account/models/account_bank_statement.py
@@ -831,6 +831,9 @@ class AccountBankStatementLine(models.Model):
             }
             st_line.process_reconciliation(new_aml_dicts=[vals])
 
+    def _get_communication(self, payment_method_id):
+        return self.name or ''
+
     def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=None, new_aml_dicts=None):
         """ Match statement lines with existing payments (eg. checks) and/or payables/receivables (eg. invoices and credit notes) and/or new move lines (eg. write-offs).
             If any new journal item needs to be created (via new_aml_dicts or counterpart_aml_dicts), a new journal entry will be created and will contain those
@@ -928,7 +931,7 @@ class AccountBankStatementLine(models.Model):
                     'state': 'reconciled',
                     'currency_id': currency.id,
                     'amount': abs(total),
-                    'communication': self.name or '',
+                    'communication': self._get_communication(payment_methods[0] if payment_methods else False),
                     'name': self.statement_id.name,
                 })
 
diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py
index 25e6449c7af27a8b9b6afada025644c476b9db16..db8c4918b81fcce79e9829ff887207fc750a4239 100644
--- a/addons/account/models/partner.py
+++ b/addons/account/models/partner.py
@@ -278,7 +278,7 @@ class ResPartner(models.Model):
 
         # generate where clause to include multicompany rules
         where_query = account_invoice_report._where_calc([
-            ('partner_id', 'in', all_partner_ids), ('state', 'not in', ['draft', 'cancel']), ('company_id', '=', self.env.user.company_id.id),
+            ('partner_id', 'in', all_partner_ids), ('state', 'not in', ['draft', 'cancel']),
             ('type', 'in', ('out_invoice', 'out_refund'))
         ])
         account_invoice_report._apply_ir_rules(where_query, 'read')
diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py
index 4753ce92a8636148750eb01d4c72c5e2c4a6b6f2..62c2fe786a1fb0e752b17ed51c95e0d88e330700 100644
--- a/addons/account/report/account_invoice_report.py
+++ b/addons/account/report/account_invoice_report.py
@@ -135,7 +135,7 @@ class AccountInvoiceReport(models.Model):
                 JOIN (
                     -- Temporary table to decide if the qty should be added or retrieved (Invoice vs Credit Note)
                     SELECT id,(CASE
-                         WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
+                         WHEN ai.type::text = ANY (ARRAY['in_refund'::character varying::text, 'in_invoice'::character varying::text])
                             THEN -1
                             ELSE 1
                         END) AS sign
diff --git a/addons/base_address_city/models/res_partner.py b/addons/base_address_city/models/res_partner.py
index e3e3ad574e0d2c43973b21c5d9c4a0768749fe60..e92867fabb488c363bb9746c808ca289d9a463ee 100644
--- a/addons/base_address_city/models/res_partner.py
+++ b/addons/base_address_city/models/res_partner.py
@@ -20,10 +20,10 @@ class Partner(models.Model):
     @api.model
     def _fields_view_get_address(self, arch):
         arch = super(Partner, self)._fields_view_get_address(arch)
-        if not self._context.get('no_address_format'):
-            return arch
         # render the partner address accordingly to address_view_id
         doc = etree.fromstring(arch)
+        if doc.xpath("//field[@name='city_id']"):
+           return arch
         for city_node in doc.xpath("//field[@name='city']"):
             replacement_xml = """
             <div>
diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py
index 268ae7e76f08dfce63bd07a75334be3fd7a8da90..bef0b88914dbe912d7d196734fa3ce5f09b61d09 100644
--- a/addons/base_automation/models/base_automation.py
+++ b/addons/base_automation/models/base_automation.py
@@ -307,7 +307,7 @@ class BaseAutomation(models.Model):
         if action.trg_date_calendar_id and action.trg_date_range_type == 'day':
             return action.trg_date_calendar_id.plan_days(
                 action.trg_date_range,
-                day_date=fields.Datetime.from_string(record_dt),
+                fields.Datetime.from_string(record_dt),
                 compute_leaves=True,
             )
         else:
diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py
index e10976af980c7ed974f248fbf4d7be49ba6e1f01..12547c8f695ac6af0ae8e06e2f550c160468a4ce 100644
--- a/addons/calendar/tests/test_calendar.py
+++ b/addons/calendar/tests/test_calendar.py
@@ -25,6 +25,20 @@ class TestCalendar(TransactionCase):
             'name': 'Technical Presentation'
         })
 
+    def test_calender_simple_event(self):
+        m = self.CalendarEvent.create({
+            'name': "Test compute",
+            'start': '2017-07-12 14:30:00',
+            'allday': False,
+            'stop': '2017-07-12 15:00:00',
+        })
+
+        self.assertEqual(
+            (m.start_datetime, m.stop_datetime),
+            (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'),
+            "Sanity check"
+        )
+
     def test_calender_event(self):
         # Now I will set recurrence for this event to occur monday and friday of week
         data = {
diff --git a/addons/event_sale/models/event.py b/addons/event_sale/models/event.py
index 9af02529ef8d3ecdeec5c83712c56ea53a80b0b3..c503ea7d44b46d3a3993448d1e28a704061d4972 100644
--- a/addons/event_sale/models/event.py
+++ b/addons/event_sale/models/event.py
@@ -5,6 +5,7 @@ from odoo import api, fields, models, _
 from odoo.exceptions import ValidationError, UserError
 
 from odoo.addons import decimal_precision as dp
+from odoo.tools import float_is_zero
 
 
 class EventType(models.Model):
@@ -222,7 +223,8 @@ class EventRegistration(models.Model):
         information.append((_('Name'), self.name))
         information.append((_('Ticket'), self.event_ticket_id.name or _('None')))
         order = self.sale_order_id.sudo()
-        if not order:
+        order_line = self.sale_order_line_id.sudo()
+        if not order or float_is_zero(order_line.price_total, precision_digits=order.currency_id.rounding):
             payment_status = _('Free')
         elif not order.invoice_ids or any(invoice.state != 'paid' for invoice in order.invoice_ids):
             payment_status = _('To pay')
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index d383c8096ea985f8d7c6b60d2a8bf6ca4f80fc9e..fd7362699684d524c711e2714540bcfa7b5d661f 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -177,10 +177,10 @@ class MailThread(models.AbstractModel):
                              RIGHT JOIN mail_channel_partner cp
                              ON (cp.channel_id = rel.mail_channel_id AND cp.partner_id = %s AND
                                 (cp.seen_message_id IS NULL OR cp.seen_message_id < msg.id))
-                             WHERE msg.model = %s AND msg.res_id in %s AND
+                             WHERE msg.model = %s AND msg.res_id = ANY(%s) AND
                                    (msg.author_id IS NULL OR msg.author_id != %s) AND
                                    (msg.message_type != 'notification' OR msg.model != 'mail.channel')""",
-                         (partner_id, self._name, tuple(self.ids) or (None,), partner_id,))
+                         (partner_id, self._name, list(self.ids), partner_id,))
         for result in self._cr.fetchall():
             res[result[0]] += 1
 
diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml
index 2b7f311a4f52bbbd366eb8e6bf61e86d7d81e9f6..d288ef43862c45b23bc33173e23cbdddd084e78d 100644
--- a/addons/project/views/project_views.xml
+++ b/addons/project/views/project_views.xml
@@ -132,7 +132,7 @@
                         </div>
                     </div>
                     <notebook>
-                        <page string="Settings">
+                        <page name="settings" string="Settings">
                             <group>
                                 <field name="user_id" string="Project Manager"
                                         attrs="{'readonly':[('active','=',False)]}"/>
@@ -149,7 +149,7 @@
                                 </group>
                             </group>
                         </page>
-                        <page string="Emails" attrs="{'invisible': [('alias_domain', '=', False)]}">
+                        <page name="emails" string="Emails" attrs="{'invisible': [('alias_domain', '=', False)]}">
                             <group name="group_alias">
                                 <label for="alias_name" string="Email Alias"/>
                                 <div name="alias_def">
@@ -443,7 +443,7 @@
                             <field name="description" type="html"/>
                             <div class="oe_clear"/>
                         </page>
-                        <page string="Extra Info">
+                        <page name="extra_info" string="Extra Info">
                             <group>
                                 <group>
                                     <field name="sequence" groups="base.group_no_one"/>
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 2481a79c1d84aaf32bfd0348c1bad26f8edbf322..4c8bee5cd81eca195cb144d84ff808026b37c8a8 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -451,13 +451,13 @@ class SaleOrder(models.Model):
     @api.multi
     def action_draft(self):
         orders = self.filtered(lambda s: s.state in ['cancel', 'sent'])
-        orders.write({
+        return orders.write({
             'state': 'draft',
         })
 
     @api.multi
     def action_cancel(self):
-        self.write({'state': 'cancel'})
+        return self.write({'state': 'cancel'})
 
     @api.multi
     def action_quotation_send(self):
@@ -508,7 +508,7 @@ class SaleOrder(models.Model):
 
     @api.multi
     def action_done(self):
-        self.write({'state': 'done'})
+        return self.write({'state': 'done'})
 
     @api.multi
     def action_unlock(self):
diff --git a/addons/web/static/src/js/chrome/search_menus.js b/addons/web/static/src/js/chrome/search_menus.js
index eee7303ffbd4eff72a301f714fafbae5629c3c07..fe2ce5f3c32135bf22eedc3c5ff17b55fc7e6cd9 100644
--- a/addons/web/static/src/js/chrome/search_menus.js
+++ b/addons/web/static/src/js/chrome/search_menus.js
@@ -415,7 +415,7 @@ return Widget.extend({
         this.groupableFields = [];
         var groupable_types = ['many2one', 'char', 'boolean', 'selection', 'date', 'datetime'];
         _.each(fields, function (field, name) {
-            if (field.store && _.contains(groupable_types, field.type)) {
+            if (field.sortable && _.contains(groupable_types, field.type)) {
                 self.groupableFields.push(_.extend({}, field, {name: name}));
             }
         });
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index dbbafe4432cc1b8b97d510968cb6306cb5f37f5d..ed5f03b4f9b1c3ccd40eafe44218c3b954ab4c27 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -372,9 +372,14 @@ var FieldMany2One = AbstractField.extend({
                 }
                 // create and edit ...
                 if (create_enabled && !self.nodeOptions.no_create_edit) {
+                    var createAndEditAction = function () {
+                        // Clear the value in case the user clicks on discard
+                        self.$('input').val('');
+                        return self._searchCreatePopup("form", false, self._createContext(search_val));
+                    };
                     values.push({
                         label: _t("Create and Edit..."),
-                        action: self._searchCreatePopup.bind(self, "form", false, self._createContext(search_val)),
+                        action: createAndEditAction,
                         classname: 'o_m2o_dropdown_option',
                     });
                 } else if (values.length === 0) {
diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js
index 82cca87f4df15a8860c322fb15456f281d9330e2..782128994db236fd3b8252c71933c282687c63e6 100644
--- a/addons/web/static/src/js/widgets/domain_selector.js
+++ b/addons/web/static/src/js/widgets/domain_selector.js
@@ -805,7 +805,7 @@ var DomainLeaf = DomainNode.extend({
             if (_.isBoolean(this.value)) {
                 this.value = "";
             } else if (_.isObject(this.value) && !_.isArray(this.value)) { // Can be object if parsed to x2x representation
-                this.value = this.value.id || "";
+                this.value = this.value.id || value || "";
             }
         }
 
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 0c910e5b4def4b81645cc5fa073711eb8a75581b..7a0937084c3c3c2c4ccfcbb9c729eee842db1331 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -1491,7 +1491,7 @@ QUnit.module('relational_fields', {
 
     QUnit.test('pressing ENTER on a \'no_quick_create\' many2one should not trigger M2ODialog', function (assert) {
         var done = assert.async();
-        assert.expect(1);
+        assert.expect(2);
 
         var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
         relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
@@ -1529,6 +1529,10 @@ QUnit.module('relational_fields', {
                 $input.blur();
                 assert.strictEqual($('.modal').length, 1,
                     "should have one modal in body");
+                // Check that discarding clears $input
+                $('.modal .o_form_button_cancel').click();
+                assert.strictEqual($input.val(), '',
+                    "the field should be empty");
                 form.destroy();
                 relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
                 done();
diff --git a/addons/web/static/tests/widgets/domain_selector_tests.js b/addons/web/static/tests/widgets/domain_selector_tests.js
index 77d8eeb24da0fc64ab625e14d69e3a725ec87a8e..55ddc971642f167deb291bf36daad1d30d361a9c 100644
--- a/addons/web/static/tests/widgets/domain_selector_tests.js
+++ b/addons/web/static/tests/widgets/domain_selector_tests.js
@@ -174,6 +174,26 @@ QUnit.module('DomainSelector', {
 
         domainSelector.destroy();
     });
+
+    QUnit.test("building a domain with a m2o without following the relation", function (assert) {
+        assert.expect(1);
+
+        var $target = $("#qunit-fixture");
+
+        // Create the domain selector and its mock environment
+        var domainSelector = new DomainSelector(null, "partner", [["product_id", "ilike", 1]], {
+            debugMode: true,
+            readonly: false,
+        });
+        testUtils.addMockEnvironment(domainSelector, {data: this.data});
+        domainSelector.appendTo($target);
+
+        domainSelector.$('.o_domain_leaf_value_input').val('pad').trigger('input').trigger('change');
+        assert.strictEqual(domainSelector.$('.o_domain_debug_input').val(), '[["product_id","ilike","pad"]]',
+            "string should have been allowed as m2o value");
+
+        domainSelector.destroy();
+    });
 });
 });
 });
diff --git a/addons/website_mail_channel/controllers/main.py b/addons/website_mail_channel/controllers/main.py
index f3e5b51847ea094718faf508f27910161de6a4fd..678defa34ef28e8a4750a897b628ab80d6544cb5 100644
--- a/addons/website_mail_channel/controllers/main.py
+++ b/addons/website_mail_channel/controllers/main.py
@@ -6,7 +6,7 @@ import werkzeug
 from datetime import datetime
 from dateutil import relativedelta
 
-from odoo import http, fields, tools
+from odoo import http, fields, tools, _
 from odoo.http import request
 from odoo.addons.http_routing.models.ir_http import slug
 
@@ -228,8 +228,16 @@ class MailGroup(http.Controller):
     def confirm_unsubscribe(self, channel, partner_id, token, **kw):
         subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
         if not subscriber:
-            # not registered, maybe already unsubsribed
-            return request.render('website_mail_channel.invalid_token_subscription')
+            # FIXME: remove try/except in master
+            try:
+                return request.render(
+                    'website_mail_channel.not_subscribed', {
+                    'partner_id': partner_id
+                })
+            except ValueError:
+                return _("The address %s is already unsubscribed or was never subscribed to any mailing list") % (
+                    partner_id.email
+                )
 
         subscriber_token = channel._generate_action_token(partner_id, action='unsubscribe')
         if token != subscriber_token:
diff --git a/addons/website_mail_channel/views/website_mail_channel_templates.xml b/addons/website_mail_channel/views/website_mail_channel_templates.xml
index 5ed8a25e9d685c42c7a9e4402815e5ebfbc73f6d..e225d107b3c8c7d963b5c160418ae8405acb5002 100644
--- a/addons/website_mail_channel/views/website_mail_channel_templates.xml
+++ b/addons/website_mail_channel/views/website_mail_channel_templates.xml
@@ -338,4 +338,19 @@
     </t>
 </template>
 
+<template id="not_subscribed" name="Email address was not subscribed">
+    <t t-call="website.layout">
+        <div id="wrap" class="oe_structure oe_empty">
+            <div class="container">
+                <p>
+                    The address <t t-esc="partner_id.email"/> is already
+                    unsubscribed or was never subscribed to the mailing
+                    list, you may want to check that the address was
+                    correct.
+                </p>
+            </div>
+        </div>
+    </t>
+</template>
+
 </odoo>
diff --git a/doc/cla/corporate/equitania.md b/doc/cla/corporate/equitania.md
new file mode 100644
index 0000000000000000000000000000000000000000..8dedd6fd05ccb7effb3a70bc457e40dbec68cf47
--- /dev/null
+++ b/doc/cla/corporate/equitania.md
@@ -0,0 +1,21 @@
+Germany, 2017-09-11
+
+Equitania Software GmbH agrees to the terms of the
+Odoo  Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Martin Schmid m.schmid@equitania.com https://github.com/eqms
+
+List of contributors:
+
+Julia Eberle j.eberle@equitania.de https://github.com/eqje
+Paul Exler p.exler@equitania.de https://github.com/eqpe
+Oliver Hercht o.hercht@equitania.de https://github.com/eqoh
+Johann Müller j.mueller@equitania.de https://github.com/eqjm
+Robin Prijatel r.prijatel@equitania.de https://github.com/eqrp
+Michal Sodomka m.sodomka@equitania.de https://github.com/eqmiso
+
diff --git a/doc/cla/corporate/merchise.md b/doc/cla/corporate/merchise.md
index 6cc3e022152f9cc114caa1319f00648bde8cc0ce..d8d5e75f8305632617e91c0c71769d101277d45b 100644
--- a/doc/cla/corporate/merchise.md
+++ b/doc/cla/corporate/merchise.md
@@ -18,3 +18,5 @@ Henrik Pestano henrik@merchise.org https://github.com/hpestano
 Oraldo Jacinto Simón oraldo@merchise.org
 Sergio Valdés sergiov@merchise.org
 Medardo Rodríguez med@merchise.org https://github.com/med-merchise
+Abel Firvida firvida@merchise.org
+Abel Firvida abel@merchise.org
diff --git a/doc/cla/corporate/quartile.md b/doc/cla/corporate/quartile.md
new file mode 100644
index 0000000000000000000000000000000000000000..b43892e12279cc6e56767e2904ffd35e845b1eb6
--- /dev/null
+++ b/doc/cla/corporate/quartile.md
@@ -0,0 +1,14 @@
+Hong Kong, 2017-09-18
+
+Quartile Limited agrees to the terms of the Odoo Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Yoshi Tashiro tashiro@quartile.co https://github.com/yostashiro
+
+List of contributors:
+
+Yoshi Tashiro tashiro@quartile.co https://github.com/yostashiro
+Tim Lai tl@quartile.co https://github.com/TimLai125
diff --git a/doc/cla/corporate/sewisoft.md b/doc/cla/corporate/sewisoft.md
new file mode 100644
index 0000000000000000000000000000000000000000..6b76b2feca1cd0911f0411d2411d92649827d3ea
--- /dev/null
+++ b/doc/cla/corporate/sewisoft.md
@@ -0,0 +1,16 @@
+Germany, 2017-07-25
+
+sewisoft UG agrees to the terms of the Odoo Corporate
+Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this 
+declaration.
+
+Signed,
+
+Günter Selbert guenter.selbert@sewisoft.de https://github.com/Guenzn
+
+List of contributors:
+
+Günter Selbert guenter.selbert@sewisoft.de https://github.com/Guenzn
+Stefan Wild stefan.wild@sewisoft.de https://github.com/wildi1
diff --git a/doc/cla/corporate/syleam.md b/doc/cla/corporate/syleam.md
index 75ac0025efe7d8132e52bcb65551b539229fd890..7c2e09760d0f151a772e18ac60dd09b03cccfacd 100644
--- a/doc/cla/corporate/syleam.md
+++ b/doc/cla/corporate/syleam.md
@@ -14,4 +14,7 @@ List of contributors:
 
 Sébastien Lange sebastien.lange@syleam.fr https://github.com/alnslang
 Sylvain Garancher sylvain.garancher@syleam.fr https://github.com/sylvain-garancher
-Alexandre Moreau alexandre.moreau@syleam.fr https://github.com/a-moreau
+Alexandre Moreau alexandre.moreau@syleam.fr https://github.com/a-moreau (Up to 2017-08-31)
+Christopher Tribbeck chris.tribbeck@syleam.fr https://github.com/ctribbeck
+Jérémy Cormier jeremy.cormier@syleam.fr https://github.com/Corbiezorq
+Samuel Piquet samuel.piquet@syleam.fr https://github.com/sa3m
diff --git a/doc/cla/corporate/tvtmarine-automation.md b/doc/cla/corporate/tvtmarine-automation.md
index 8b5b59d501b2011f802167c65e726d71d6bc4752..de0906f033162bcc0f4480ef8705d8bdeea98853 100644
--- a/doc/cla/corporate/tvtmarine-automation.md
+++ b/doc/cla/corporate/tvtmarine-automation.md
@@ -14,4 +14,6 @@ List of contributors:
 
 David Tran david.tran@tvtmarine.com https://github.com/davidtranhp
 Long Do dhlong.1209@gmail.com https://github.com/hoanglong87
-Hao Hoang hao.hoang@ma.tvtmarine.com https://github.com/hoanghao2001
\ No newline at end of file
+Hao Hoang hao.hoang@ma.tvtmarine.com https://github.com/hoanghao2001
+Tommy Tran tu.tran@tvtmarine.com https://github.com/tutran81
+Emily Ha emily.ha@tvtmarine.com https://github.com/emilyha
\ No newline at end of file
diff --git a/doc/cla/corporate/vauxoo.md b/doc/cla/corporate/vauxoo.md
index 096c835ef552158779616cde48094f48dfe3f7cf..017ffe08bbad84da20a6517ad445214915b7f146 100644
--- a/doc/cla/corporate/vauxoo.md
+++ b/doc/cla/corporate/vauxoo.md
@@ -38,3 +38,4 @@ Gabriela Mogollon gmogollon@vauxoo.com https://github.com/GavyMG
 Jesus Zapata jesus@vauxoo.com https://github.com/JesusZapata
 Germana Oliveira germana@vauxoo.com https://github.com/goliveirab
 Mariano Fernandez mariano@vauxoo.com https://github.com/Batuto
+Edgar Rivero edgar@vauxoo.com https://github.com/egrivero
diff --git a/doc/cla/corporate/xoe-corp.md b/doc/cla/corporate/xoe-corp.md
new file mode 100644
index 0000000000000000000000000000000000000000..ef449e25d72cd3b69a13b0ab5b028000438a8344
--- /dev/null
+++ b/doc/cla/corporate/xoe-corp.md
@@ -0,0 +1,15 @@
+Colombia, 2016-04-20
+
+Xoe Corp SAS. agrees to the terms of the Odoo Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+David Arnold dar@xoe.solutions https://github.com/blaggacao
+
+List of contributors:
+
+David Arnold dar@devco.co https://github.com/blaggacao
diff --git a/doc/cla/individual/bazemoreb.md b/doc/cla/individual/bazemoreb.md
new file mode 100644
index 0000000000000000000000000000000000000000..c800a883ceecdec605078a468720fe8d1a5115a0
--- /dev/null
+++ b/doc/cla/individual/bazemoreb.md
@@ -0,0 +1,11 @@
+USA, 2017-10-01
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Brandon Bazemore brandonb@audian.com  https://github.com/bazemoreb
diff --git a/doc/cla/individual/blaggacao.md b/doc/cla/individual/blaggacao.md
new file mode 100644
index 0000000000000000000000000000000000000000..30b2fee69a0e4a1b0f4d5603dec9cf017aab2914
--- /dev/null
+++ b/doc/cla/individual/blaggacao.md
@@ -0,0 +1,12 @@
+Colombia, 2017-09-01
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+David Arnold dar@xoe.solutions https://github.com/blaggacao
+
diff --git a/doc/cla/individual/danger89.md b/doc/cla/individual/danger89.md
new file mode 100644
index 0000000000000000000000000000000000000000..11c9e89616c4936acef98e40c54e5221000d5ac0
--- /dev/null
+++ b/doc/cla/individual/danger89.md
@@ -0,0 +1,11 @@
+The Netherlands, 2017-10-02
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Melroy van den Berg webmaster1989@gmail.com https://github.com/danger89
diff --git a/doc/cla/individual/hansmi.md b/doc/cla/individual/hansmi.md
new file mode 100644
index 0000000000000000000000000000000000000000..ff47950308312de4d8f4ebe626914c623b5e30c0
--- /dev/null
+++ b/doc/cla/individual/hansmi.md
@@ -0,0 +1,11 @@
+Switzerland, 2017-09-15
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Michael Hanselmann public@hansmi.ch https://github.com/hansmi
diff --git a/odoo/addons/base/res/res_currency_data.xml b/odoo/addons/base/res/res_currency_data.xml
index 75efdb752a92c915809926c1ce15825bef688b6d..d158a91ce9b262af0d0c8ff87952dc95235c05ea 100644
--- a/odoo/addons/base/res/res_currency_data.xml
+++ b/odoo/addons/base/res/res_currency_data.xml
@@ -99,6 +99,7 @@
             <field name="name">IDR</field>
             <field name="symbol">Rp</field>
             <field name="rounding">0.01</field>
+            <field name="position">before</field>
             <field name="active" eval="False"/>
             <field name="currency_unit_label">Rupiah</field>
             <field name="currency_subunit_label">Sen</field>
diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py
index f99f9b466eb65e09cc7d830fda2e7ca9f35717a7..73ba36f481343df74dcdc5bba7e46e3ac9872dd6 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -712,6 +712,30 @@ class TestFields(common.TransactionCase):
         self.assertFalse(discussion.very_important_messages)
         self.assertFalse(message.exists())
 
+    def test_70_x2many_write(self):
+        discussion = self.env.ref('test_new_api.discussion_0')
+        Message = self.env['test_new_api.message']
+        # There must be 3 messages, 0 important
+        self.assertEqual(len(discussion.messages), 3)
+        self.assertEqual(len(discussion.important_messages), 0)
+        self.assertEqual(len(discussion.very_important_messages), 0)
+        discussion.important_messages = [(0, 0, {
+            'body': 'What is the answer?',
+            'important': True,
+        })]
+        # There must be 4 messages, 1 important
+        self.assertEqual(len(discussion.messages), 4)
+        self.assertEqual(len(discussion.important_messages), 1)
+        self.assertEqual(len(discussion.very_important_messages), 1)
+        discussion.very_important_messages |= Message.new({
+            'body': '42',
+            'important': True,
+        })
+        # There must be 5 messages, 2 important
+        self.assertEqual(len(discussion.messages), 5)
+        self.assertEqual(len(discussion.important_messages), 2)
+        self.assertEqual(len(discussion.very_important_messages), 2)
+
 
 class TestX2many(common.TransactionCase):
     def test_search_many2many(self):
diff --git a/odoo/fields.py b/odoo/fields.py
index 780a1c318bca2d6e10470a60d80e75cf495ab253..bef9ba4302a17bec915d4e3d01b9475949f9830e 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -39,18 +39,23 @@ Default = object()                      # default value for __init__() methods
 
 def copy_cache(records, env):
     """ Recursively copy the cache of ``records`` to the environment ``env``. """
-    src, dst = records.env.cache, env.cache
-    todo, done = set(records), set()
+    src = records.env
+    todo = defaultdict(set)             # {model_name: ids}
+    done = defaultdict(set)             # {model_name: ids}
+    todo[records._name].update(records._ids)
     while todo:
-        record = todo.pop()
-        if record not in done:
-            done.add(record)
-            target = record.with_env(env)
-            for field in src.get_fields(record):
-                value = src.get(record, field)
-                dst.set(target, field, value)
-                if value and field.type in ('many2one', 'one2many', 'many2many', 'reference'):
-                    todo.update(field.convert_to_record(value, record))
+        model_name = next(iter(todo))
+        record_ids = todo.pop(model_name) - done[model_name]
+        done[model_name].update(record_ids)
+        for name, field in src[model_name]._fields.items():
+            src_cache = src.cache[field]
+            dst_cache = env.cache[field]
+            for record_id in record_ids:
+                if record_id in src_cache:
+                    # copy the cached value as such
+                    value = dst_cache[record_id] = src_cache[record_id]
+                    if field.relational and isinstance(value, tuple):
+                        todo[field.comodel_name].update(value)
 
 
 def resolve_mro(model, name, predicate):
@@ -2245,14 +2250,13 @@ class One2many(_RelationalMulti):
                 elif act[0] == 6:
                     record = records[-1]
                     comodel.browse(act[2]).write({inverse: record.id})
-                    query = "SELECT id FROM %s WHERE %s=%%s AND id <> ALL(%%s)" % (comodel._table, inverse)
-                    comodel._cr.execute(query, (record.id, act[2] or [0]))
-                    lines = comodel.browse([row[0] for row in comodel._cr.fetchall()])
+                    domain = self.domain(records) if callable(self.domain) else self.domain
+                    domain = domain + [(inverse, 'in', records.ids), ('id', 'not in', act[2] or [0])]
                     inverse_field = comodel._fields[inverse]
                     if inverse_field.ondelete == 'cascade':
-                        lines.unlink()
+                        comodel.search(domain).unlink()
                     else:
-                        lines.write({inverse: False})
+                        comodel.search(domain).write({inverse: False})
 
 
 class Many2many(_RelationalMulti):