diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 4f5354784a8..213cea0c6fa 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -273,6 +273,14 @@ class Lead(models.Model): # ORM override (CRUD, fields_view_get, ...) # ---------------------------------------- + @api.model + def name_create(self, name): + res = super(Lead, self).name_create(name) + + # update the probability of the lead if the stage is set to update it automatically + self.browse(res[0])._onchange_stage_id() + return res + @api.model def create(self, vals): # set up context used to find the lead's sales channel which is needed diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index fff0436699f..947520b4f03 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -340,7 +340,8 @@ ('activity_ids.date_deadline', '<=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')) ]"/> @@ -583,10 +584,10 @@ ('activity_ids.date_deadline', '<=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')) ]"/> diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 8c3df12f12c..47a92e018b5 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -87,9 +87,8 @@ class MailController(http.Controller): record_sudo.sudo(uid).check_access_rule('read') except AccessError: return cls._redirect_to_messaging() - - if record_action['type'] == 'ir.actions.act_url': - return werkzeug.utils.redirect(record_action['url']) + if record_action['type'] == 'ir.actions.act_url': + return werkzeug.utils.redirect(record_action['url']) url_params = { 'view_type': record_action['view_type'], diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 27281342cde..043188b6393 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1475,7 +1475,7 @@ exports.Orderline = Backbone.Model.extend({ var recompute_base = function(base_amount, fixed_amount, percent_amount){ if(fixed_amount === 0.0 && percent_amount === 0.0) return base_amount; - return round_pr((base_amount - fixed_amount) / (1.0 + percent_amount / 100.0), currency_rounding); + return (base_amount - fixed_amount) / (1.0 + percent_amount / 100.0); } // 4) Iterate the taxes in the reversed sequence order to retrieve the initial base of the computation. @@ -1529,7 +1529,6 @@ exports.Orderline = Backbone.Model.extend({ taxes_vals.push(tax_vals); }); - return { taxes: taxes_vals, total_excluded: round_pr(total_excluded, currency_rounding_bak), diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index ae39d48e47e..01cbe71df5c 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -868,7 +868,7 @@ class SaleOrderLine(models.Model): return price else: from_currency = self.order_id.company_id.currency_id - return from_currency.compute(product[pricelist_item.base], self.order_id.pricelist_id.currency_id) + return from_currency.compute(pricelist_item and product[pricelist_item.base] or product.lst_price, self.order_id.pricelist_id.currency_id) @api.multi @api.onchange('product_id') diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 38e59b78cc5..087c111499a 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -968,7 +968,7 @@ class StockMove(models.Model): self._propagate_split(new_move, qty) # returning the first element of list returned by action_confirm is ok because we checked it wouldn't be exploded (and # thus the result of action_confirm should always be a list of 1 element length) - new_move.action_confirm() + new_move = new_move.action_confirm() # TDE FIXME: due to action confirm change return new_move.id diff --git a/addons/web_editor/static/src/js/rte.js b/addons/web_editor/static/src/js/rte.js index c7dc268251d..13eb568f9b7 100644 --- a/addons/web_editor/static/src/js/rte.js +++ b/addons/web_editor/static/src/js/rte.js @@ -578,6 +578,28 @@ var RTE = Widget.extend({ _.defer(function () { self.historyRecordUndo($target, 'activate', true); }); + + // To Fix Google Chrome Tripleclick Issue, which selects the ending + // whitespace characters (so Tripleclicking then typing text will remove + // the whole paragraph instead of its content). + // http://stackoverflow.com/questions/38467334/why-does-google-chrome-always-add-space-after-selected-text + if ($.browser.chrome === true && event.originalEvent.detail === 3) { + var currentSelection = range.create(); + if (currentSelection.sc.parentNode === currentSelection.ec) { + _selectSC(currentSelection); + } else if (currentSelection.eo === 0) { + var $hasNext = $(currentSelection.sc).parent(); + while (!$hasNext.next().length && !$hasNext.is('body')) { + $hasNext = $hasNext.parent(); + } + if ($hasNext.next()[0] === currentSelection.ec) { + _selectSC(currentSelection); + } + } + } + function _selectSC(selection) { + range.create(selection.sc, selection.so, selection.sc, selection.sc.length).select(); + } }, editable: function () { diff --git a/addons/web_editor/static/src/less/web_editor.common.less b/addons/web_editor/static/src/less/web_editor.common.less index c48fdf7df46..973b04dbf2d 100644 --- a/addons/web_editor/static/src/less/web_editor.common.less +++ b/addons/web_editor/static/src/less/web_editor.common.less @@ -23,7 +23,9 @@ html, body { /* ----- GENERIC LAYOUTING HELPERS ---- */ /* table */ #wrapwrap, .o_editable { - table.table { + // Only style editor-made tables (shop/portal/... tables are not supposed to + // use table-bordered...) + table.table.table-bordered { table-layout: fixed; td { min-width: 20px; diff --git a/addons/website_quote/models/__init__.py b/addons/website_quote/models/__init__.py index 011bafd821f..a83051f5a10 100644 --- a/addons/website_quote/models/__init__.py +++ b/addons/website_quote/models/__init__.py @@ -4,3 +4,4 @@ import sale_order import sale_quote import product_template +import ir_model_fields diff --git a/addons/website_quote/models/ir_model_fields.py b/addons/website_quote/models/ir_model_fields.py new file mode 100644 index 00000000000..55643edfe0d --- /dev/null +++ b/addons/website_quote/models/ir_model_fields.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + +# !! Attention, this is a hack of a hack, do not try this at home !! +# This is done because website_quote defines the website_description +# field which is also defined by website_sale, but these two modules +# are independent of each other, the part of the ORM that generates +# xmlids does not support this case therefore it only creates a single +# pair of xmlids for whichever module is installed first, therefore +# when uninstalling any of the two modules the website_descripion field +# will be deleted from the db and the other module won't be able to +# use this field, resulting in a crash and data-loss. +# See opw-776464 for more details. +# +# This is hotfixed by overriding the unlink method so as to not delete +# the website_description field if website_quote is uninstalled, it's +# an ugly hack but it works and big changes can't be done to the ORM +# in stable versions, Odoo v12+ will properly fix this + + +class IrModelFields(models.Model): + _inherit = "ir.model.fields" + + @api.multi + def unlink(self): + # Prevent the deletion of the field "website_description" + self = self.filtered( + lambda rec: not ( + rec.model in ('product.product', 'product.template') and + rec.name == 'website_description' + ) + ) + return super(IrModelFields, self).unlink() diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index 6c50e86c2b1..8d33629e927 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -3,6 +3,7 @@ from odoo import api, fields, models, tools, _ import odoo.addons.decimal_precision as dp from odoo.tools.translate import html_translate +from odoo.tools import float_is_zero class ProductStyle(models.Model): @@ -139,6 +140,7 @@ class ProductTemplate(models.Model): website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) + website_price_difference = fields.Boolean('Website price difference', compute='_website_price') def _website_price(self): # First filter out the ones that have no variant: @@ -148,6 +150,7 @@ class ProductTemplate(models.Model): for template, product in zip(self, self.mapped('product_variant_id')): template.website_price = product.website_price template.website_public_price = product.website_public_price + template.website_price_difference = product.website_price_difference def _default_website_sequence(self): self._cr.execute("SELECT MIN(website_sequence) FROM %s" % self._table) @@ -188,6 +191,7 @@ class Product(models.Model): website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) + website_price_difference = fields.Boolean('Website price difference', compute='_website_price') def _website_price(self): qty = self._context.get('quantity', 1.0) @@ -204,6 +208,8 @@ class Product(models.Model): for p, p2 in zip(self, self2): taxes = partner.property_account_position_id.map_tax(p.taxes_id.sudo().filtered(lambda x: x.company_id == company_id)) p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret] + price_without_pricelist = taxes.compute_all(p.list_price, pricelist.currency_id)[ret] + p.website_price_difference = False if float_is_zero(price_without_pricelist - p.website_price, precision_rounding=pricelist.currency_id.rounding) else True p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret] @api.multi diff --git a/addons/website_sale/static/src/js/website_sale_payment.js b/addons/website_sale/static/src/js/website_sale_payment.js index 526145bba8d..39cbea8d165 100644 --- a/addons/website_sale/static/src/js/website_sale_payment.js +++ b/addons/website_sale/static/src/js/website_sale_payment.js @@ -6,10 +6,10 @@ var ajax = require('web.ajax'); $(document).ready(function () { // If option is enable if ($("#checkbox_cgv").length) { - var enabling_button = function() { + $("#checkbox_cgv").change(function() { $("div.oe_sale_acquirer_button").find('input, button').prop("disabled", !this.checked); - }; - $("#checkbox_cgv").click(enabling_button).each(enabling_button); + }); + $('#checkbox_cgv').trigger('change'); } // When choosing an acquirer, display its Pay Now button diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 42fc4b30623..edc3c928f24 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -104,7 +104,7 @@
- + @@ -595,7 +595,7 @@

@@ -1002,7 +1002,7 @@