summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-01-29 11:57:06 +0100
committerChristophe Simonis <chs@odoo.com>2019-01-29 11:57:06 +0100
commit36d96e015032d42449fe149c050df75050276fdc (patch)
treed70144f0a11306b04f4fa776be16cf5df535c2be
parent428546bc023db95b2128149a91c478e2be35ac39 (diff)
parent788684a5ddcff074e239b524e043cbf900dc54a9 (diff)
[MERGE] forward port branch saas-15 up to 788684a5ddc
-rw-r--r--addons/account/models/account_invoice.py21
-rw-r--r--addons/account/tests/test_account_customer_invoice.py56
-rw-r--r--addons/point_of_sale/static/src/js/models.js20
-rw-r--r--addons/point_of_sale/static/src/js/screens.js11
-rw-r--r--addons/web/static/src/js/services/crash_manager.js35
-rw-r--r--addons/web/static/src/less/navbar.less6
-rw-r--r--addons/website_slides/controllers/main.py2
7 files changed, 131 insertions, 20 deletions
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index dfaa6e5944d..1e6bff22886 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1266,6 +1266,20 @@ class AccountInvoice(models.Model):
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']
@@ -1311,7 +1325,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 50e08006cd4..7799f70f13c 100644
--- a/addons/account/tests/test_account_customer_invoice.py
+++ b/addons/account/tests/test_account_customer_invoice.py
@@ -164,3 +164,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 11d769967ba..a59710df6e7 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -892,12 +892,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 139a05459f7..08262f73336 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -2078,6 +2078,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/web/static/src/js/services/crash_manager.js b/addons/web/static/src/js/services/crash_manager.js
index d903b5870c5..9e4d5e7b3fe 100644
--- a/addons/web/static/src/js/services/crash_manager.js
+++ b/addons/web/static/src/js/services/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,16 +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() {
- var options = {shadow: true};
- ajax.jsonRpc('/web/webclient/version_info', 'call', {}, options).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 cf14f9a8615..b280ad45173 100644
--- a/addons/web/static/src/less/navbar.less
+++ b/addons/web/static/src/less/navbar.less
@@ -155,7 +155,6 @@
position: relative;
height: @odoo-navbar-height;
- overflow: hidden;
> ul {
> li {
@@ -171,6 +170,7 @@
&.o_menu_sections {
width: 100%;
+ display: none;
> li.open .dropdown-menu {
position: static;
@@ -219,6 +219,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 2ef722104b5..599f68deaec 100644
--- a/addons/website_slides/controllers/main.py
+++ b/addons/website_slides/controllers/main.py
@@ -182,7 +182,7 @@ class WebsiteSlides(http.Controller):
@http.route('''/slides/slide/<model("slide.slide"):slide>/download''', type='http', auth="public", website=True, sitemap=False)
def slide_download(self, slide, **kw):
slide = slide.sudo()
- 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(