diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 7cd59d4300a05e9b1bd9ba975eb70a47142729a4..04efbebf557189ef5a0a5568a1d83e6e16a6e0a7 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1004,6 +1004,21 @@ class AccountInvoice(models.Model):
             result.append((0, 0, values))
         return result
 
+    @api.model
+    def _refund_tax_lines_account_change(self, lines, taxes_to_change):
+        # Let's change the account on tax lines when
+        # @param {list} lines: a list of orm commands
+        # @param {dict} taxes_to_change
+        #   key: tax ID, value: refund account
+
+        if not taxes_to_change:
+            return lines
+
+        for line in lines:
+            if isinstance(line[2], dict) and line[2]['tax_id'] in taxes_to_change:
+                line[2]['account_id'] = taxes_to_change[line[2]['tax_id']]
+        return lines
+
     def _get_refund_common_fields(self):
         return ['partner_id', 'payment_term_id', 'account_id', 'currency_id', 'journal_id']
 
@@ -1045,7 +1060,12 @@ class AccountInvoice(models.Model):
         values['invoice_line_ids'] = self._refund_cleanup_lines(invoice.invoice_line_ids)
 
         tax_lines = invoice.tax_line_ids
-        values['tax_line_ids'] = self._refund_cleanup_lines(tax_lines)
+        taxes_to_change = {
+            line.tax_id.id: line.tax_id.refund_account_id.id
+            for line in tax_lines.filtered(lambda l: l.tax_id.refund_account_id != l.tax_id.account_id)
+        }
+        cleaned_tax_lines = self._refund_cleanup_lines(tax_lines)
+        values['tax_line_ids'] = self._refund_tax_lines_account_change(cleaned_tax_lines, taxes_to_change)
 
         if journal_id:
             journal = self.env['account.journal'].browse(journal_id)
diff --git a/addons/account/tests/test_account_customer_invoice.py b/addons/account/tests/test_account_customer_invoice.py
index 12a164cd3cb2755127d3371d70bd1482a92fb20c..6c6c6a253faed52ccf8586ff5e532d4631f26737 100644
--- a/addons/account/tests/test_account_customer_invoice.py
+++ b/addons/account/tests/test_account_customer_invoice.py
@@ -170,3 +170,59 @@ class TestAccountCustomerInvoice(AccountTestUsers):
         ))
 
         self.assertEquals(invoice.amount_untaxed, sum([x.base for x in invoice.tax_line_ids]))
+
+    def test_customer_invoice_tax_refund(self):
+        company = self.env.user.company_id
+        tax_account = self.env['account.account'].create({
+            'name': 'TAX',
+            'code': 'TAX',
+            'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
+            'company_id': company.id,
+        })
+
+        tax_refund_account = self.env['account.account'].create({
+            'name': 'TAX_REFUND',
+            'code': 'TAX_R',
+            'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
+            'company_id': company.id,
+        })
+
+        journalrec = self.env['account.journal'].search([('type', '=', 'sale')])[0]
+        partner3 = self.env.ref('base.res_partner_3')
+        account_id = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1).id
+
+        tax = self.env['account.tax'].create({
+            'name': 'Tax 15.0',
+            'amount': 15.0,
+            'amount_type': 'percent',
+            'type_tax_use': 'sale',
+            'account_id': tax_account.id,
+            'refund_account_id': tax_refund_account.id
+        })
+
+        invoice_line_data = [
+            (0, 0,
+                {
+                    'product_id': self.env.ref('product.product_product_1').id,
+                    'quantity': 40.0,
+                    'account_id': account_id,
+                    'name': 'product test 1',
+                    'discount': 10.00,
+                    'price_unit': 2.27,
+                    'invoice_line_tax_ids': [(6, 0, [tax.id])],
+                }
+             )]
+
+        invoice = self.env['account.invoice'].create(dict(
+            name="Test Customer Invoice",
+            reference_type="none",
+            journal_id=journalrec.id,
+            partner_id=partner3.id,
+            invoice_line_ids=invoice_line_data
+        ))
+
+        invoice.action_invoice_open()
+
+        refund = invoice.refund()
+        self.assertEqual(invoice.tax_line_ids.mapped('account_id'), tax_account)
+        self.assertEqual(refund.tax_line_ids.mapped('account_id'), tax_refund_account)
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
index fa6215ee0e87f1ad4eb86a06d2ea19c2458c3e84..2fe1efe8bfa25149c4f5cfa2a530f169b595d088 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -741,12 +741,20 @@ exports.PosModel = Backbone.Model.extend({
             transfer.pipe(function(order_server_id){    
 
                 // generate the pdf and download it
-                self.chrome.do_action('point_of_sale.pos_invoice_report',{additional_context:{ 
-                    active_ids:order_server_id,
-                }}).done(function () {
-                    invoiced.resolve();
-                    done.resolve();
-                });
+                if (order_server_id.length) {
+                    self.chrome.do_action('point_of_sale.pos_invoice_report',{additional_context:{ 
+                        active_ids:order_server_id,
+                    }}).done(function () {
+                        invoiced.resolve();
+                        done.resolve();
+                    });
+                } else {
+                    // The order has been pushed separately in batch when
+                    // the connection came back.
+                    // The user has to go to the backend to print the invoice
+                    invoiced.reject({code:401, message:'Backend Invoice', data:{order: order}});
+                    done.reject();
+                }
             });
 
             return done;
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index 82e6fa0e7b25f2b0a2c5963a01a8c08d21f3c08d..2b397e10a2e21065222aa4082e0fa84a497ba080 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -2012,6 +2012,17 @@ var PaymentScreenWidget = ScreenWidget.extend({
                             self.gui.show_screen('clientlist');
                         },
                     });
+                } else if (error.message === 'Backend Invoice') {
+                    self.gui.show_popup('confirm',{
+                        'title': _t('Please print the invoice from the backend'),
+                        'body': _t('The order has been synchronized earlier. Please make the invoice from the backend for the order: ') + error.data.order.name,
+                        confirm: function () {
+                            this.gui.show_screen('receipt');
+                        },
+                        cancel: function () {
+                            this.gui.show_screen('receipt');
+                        },
+                    });
                 } else if (error.code < 0) {        // XmlHttpRequest Errors
                     self.gui.show_popup('error',{
                         'title': _t('The order could not be sent'),
diff --git a/addons/pos_discount/static/src/js/discount.js b/addons/pos_discount/static/src/js/discount.js
index 7ef38d6ffdbc2349393a0c9996ac472b55591b28..f29cf7968451920a049ecdf7ab2adffb391c8778 100644
--- a/addons/pos_discount/static/src/js/discount.js
+++ b/addons/pos_discount/static/src/js/discount.js
@@ -23,6 +23,13 @@ var DiscountButton = screens.ActionButtonWidget.extend({
         var order    = this.pos.get_order();
         var lines    = order.get_orderlines();
         var product  = this.pos.db.get_product_by_id(this.pos.config.discount_product_id[0]);
+        if (product === undefined) {
+            this.gui.show_popup('error', {
+                title : _t("No discount product found"),
+                body  : _t("The discount product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'."),
+            });
+            return;
+        }
 
         // Remove existing discounts
         var i = 0;
diff --git a/addons/web/static/src/js/framework/crash_manager.js b/addons/web/static/src/js/framework/crash_manager.js
index baf577b578de52a90f292f00c60b652bd2dbd0c0..36d8057a23c82cd90469a4e67c95e6017cd9b6c2 100644
--- a/addons/web/static/src/js/framework/crash_manager.js
+++ b/addons/web/static/src/js/framework/crash_manager.js
@@ -22,6 +22,7 @@ var map_title ={
 var CrashManager = core.Class.extend({
     init: function() {
         this.active = true;
+        this.isConnected = true;
     },
     enable: function () {
         this.active = true;
@@ -29,8 +30,29 @@ var CrashManager = core.Class.extend({
     disable: function () {
         this.active = false;
     },
-    rpc_error: function(error) {
+    handleLostConnection: function () {
         var self = this;
+        if (!this.isConnected) {
+            // already handled, nothing to do.  This can happen when several
+            // rpcs are done in parallel and fail because of a lost connection.
+            return;
+        }
+        this.isConnected = false;
+        var delay = 2000;
+        core.bus.trigger('connection_lost');
+
+        setTimeout(function checkConnection() {
+            ajax.jsonRpc('/web/webclient/version_info', 'call', {}, {shadow:true}).then(function () {
+                core.bus.trigger('connection_restored');
+                self.isConnected = true;
+            }).fail(function () {
+                // exponential backoff, with some jitter
+                delay = (delay * 1.5) + 500*Math.random();
+                setTimeout(checkConnection, delay);
+            });
+        }, delay);
+    },
+    rpc_error: function(error) {
         if (!this.active) {
             return;
         }
@@ -38,15 +60,7 @@ var CrashManager = core.Class.extend({
             return;
         }
         if (error.code === -32098) {
-            core.bus.trigger('connection_lost');
-            this.connection_lost = true;
-            var timeinterval = setInterval(function() {
-                ajax.jsonRpc('/web/webclient/version_info').then(function() {
-                    clearInterval(timeinterval);
-                    core.bus.trigger('connection_restored');
-                    self.connection_lost = false;
-                });
-            }, 2000);
+            this.handleLostConnection();
             return;
         }
         var handler = core.crash_registry.get(error.data.name, true);
diff --git a/addons/web/static/src/less/navbar.less b/addons/web/static/src/less/navbar.less
index 5f3aff0b98fd986178bd39a56051cd0231f1455b..7b31ec1108930bd37327aaa02cbde7bac4881713 100644
--- a/addons/web/static/src/less/navbar.less
+++ b/addons/web/static/src/less/navbar.less
@@ -94,7 +94,6 @@
 
         position: relative;
         height: @odoo-navbar-height;
-        overflow: hidden;
 
         > ul {
             > li {
@@ -110,6 +109,7 @@
 
             &.o_menu_sections {
                 width: 100%;
+                display: none;
 
                 > li.open .dropdown-menu {
                     position: static;
@@ -158,6 +158,10 @@
         .o_main_navbar {
             height: 100%;
             overflow: auto;
+
+            .o_menu_sections {
+                display: block;
+            }
         }
     }
 }
diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py
index 7b67bfcbb403993b57b2ea8a76c14072b9208003..3dfe07e9734088d554f23337b7271b308d6da37b 100644
--- a/addons/website_slides/controllers/main.py
+++ b/addons/website_slides/controllers/main.py
@@ -216,7 +216,7 @@ class WebsiteSlides(http.Controller):
 
     @http.route('''/slides/slide/<model("slide.slide", "[('channel_id.can_see', '=', True), ('download_security', '=', 'public')]"):slide>/download''', type='http', auth="public", website=True)
     def slide_download(self, slide):
-        if slide.download_security == 'public' or (slide.download_security == 'user' and request.session.uid):
+        if slide.download_security == 'public' or (slide.download_security == 'user' and request.env.user and request.env.user != request.website.user_id):
             filecontent = base64.b64decode(slide.datas)
             disposition = 'attachment; filename=%s.pdf' % werkzeug.urls.url_quote(slide.name)
             return request.make_response(