diff --git a/addons/account/views/account_portal_templates.xml b/addons/account/views/account_portal_templates.xml index 51c4177f528..244eb53ac40 100644 --- a/addons/account/views/account_portal_templates.xml +++ b/addons/account/views/account_portal_templates.xml @@ -57,7 +57,7 @@ - + diff --git a/addons/account_payment/views/account_portal_templates.xml b/addons/account_payment/views/account_portal_templates.xml index 37366eba917..5fb062ff506 100644 --- a/addons/account_payment/views/account_portal_templates.xml +++ b/addons/account_payment/views/account_portal_templates.xml @@ -5,7 +5,7 @@ - + diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 1e89fe99c0f..3b36e1872d7 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -1237,7 +1237,12 @@ class Meeting(models.Model): def _rrule_parse(self, rule_str, data, date_start): day_list = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su'] rrule_type = ['yearly', 'monthly', 'weekly', 'daily'] - rule = rrule.rrulestr(rule_str, dtstart=fields.Datetime.from_string(date_start)) + ddate = fields.Datetime.from_string(date_start) + if 'Z' in rule_str and not ddate.tzinfo: + ddate = ddate.replace(tzinfo=pytz.timezone('UTC')) + rule = rrule.rrulestr(rule_str, dtstart=ddate) + else: + rule = rrule.rrulestr(rule_str, dtstart=ddate) if rule._freq > 0 and rule._freq < 4: data['rrule_type'] = rrule_type[rule._freq] diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index 1548ddfacba..80994d946fa 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -194,7 +194,6 @@ - diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index d58c77972f1..c071f23c5b2 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -159,7 +159,7 @@ class StockPicking(models.Model): def send_to_shipper(self): self.ensure_one() res = self.carrier_id.send_shipping(self)[0] - if self.carrier_id.free_over and self.sale_id._compute_amount_total_without_delivery() >= self.carrier_id.amount: + if self.carrier_id.free_over and self.sale_id and self.sale_id._compute_amount_total_without_delivery() >= self.carrier_id.amount: res['exact_price'] = 0.0 self.carrier_price = res['exact_price'] self.carrier_tracking_ref = res['tracking_number'] diff --git a/addons/http_routing/geoipresolver.py b/addons/http_routing/geoipresolver.py index 1f9b0e22724..e95b9318eb2 100644 --- a/addons/http_routing/geoipresolver.py +++ b/addons/http_routing/geoipresolver.py @@ -47,10 +47,14 @@ class GeoIPResolver(object): r = self._db.city(ip) except (ValueError, geoip2.errors.AddressNotFoundError): return {} + # Compatibility with Legacy database. + # Some ips cannot be located to a specific country. Legacy DB used to locate them in + # continent instead of country. Do the same to not change behavior of existing code. + country = r.country if r.country.geoname_id else r.continent return { 'city': r.city.name, - 'country_code': r.country.iso_code, - 'country_name': r.country.name, + 'country_code': country.iso_code, + 'country_name': country.name, 'region': r.subdivisions[0].iso_code if r.subdivisions else None, 'time_zone': r.location.time_zone, } diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 66dfcd84f8e..f675f147cb1 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -1748,6 +1748,8 @@ class MailThread(models.AbstractModel): continue if isinstance(content, pycompat.text_type): content = content.encode('utf-8') + elif content is None: + continue data_attach = { 'name': name, 'datas': base64.b64encode(content), diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index 3b15e51d44f..c28093f826f 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -14,6 +14,7 @@ from werkzeug import urls from odoo import api, fields, models, tools, _ from odoo.addons.payment.models.payment_acquirer import ValidationError from odoo.addons.payment_adyen.controllers.main import AdyenController +from odoo.tools.pycompat import to_native _logger = logging.getLogger(__name__) @@ -192,7 +193,7 @@ class TxAdyen(models.Model): shasign_check = tx.acquirer_id._adyen_generate_merchant_sig_sha256('out', data) else: shasign_check = tx.acquirer_id._adyen_generate_merchant_sig('out', data) - if shasign_check != data.get('merchantSig'): + if to_native(shasign_check) != to_native(data.get('merchantSig')): error_msg = _('Adyen: invalid merchantSig, received %s, computed %s') % (data.get('merchantSig'), shasign_check) _logger.warning(error_msg) raise ValidationError(error_msg) diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 30baa7d4498..ac016433fcb 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -175,7 +175,7 @@ class PosOrder(models.Model): 'comment': self.note or '', # considering partner's sale pricelist's currency 'currency_id': self.pricelist_id.currency_id.id, - 'user_id': self.env.uid, + 'user_id': self.user_id.id, } @api.model diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 0b2d94dd71f..1b59aa34cba 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -1172,9 +1172,11 @@ var ClientListScreenWidget = ScreenWidget.extend({ var order = this.pos.get_order(); if( this.has_client_changed() ){ var default_fiscal_position_id = _.findWhere(this.pos.fiscal_positions, {'id': this.pos.config.default_fiscal_position_id[0]}); - if ( this.new_client && this.new_client.property_account_position_id ) { - var client_fiscal_position_id = _.findWhere(this.pos.fiscal_positions, {'id': this.new_client.property_account_position_id[0]}); - order.fiscal_position = client_fiscal_position_id || default_fiscal_position_id; + if ( this.new_client ) { + if (this.new_client.property_account_position_id ){ + var client_fiscal_position_id = _.findWhere(this.pos.fiscal_positions, {'id': this.new_client.property_account_position_id[0]}); + order.fiscal_position = client_fiscal_position_id || default_fiscal_position_id; + } order.set_pricelist(_.findWhere(this.pos.pricelists, {'id': this.new_client.property_product_pricelist[0]}) || this.pos.default_pricelist); } else { order.fiscal_position = default_fiscal_position_id; diff --git a/addons/point_of_sale/views/report_saledetails.xml b/addons/point_of_sale/views/report_saledetails.xml index dea4d1a9e62..89ebc22648c 100644 --- a/addons/point_of_sale/views/report_saledetails.xml +++ b/addons/point_of_sale/views/report_saledetails.xml @@ -22,7 +22,8 @@ - + + diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 08995f2aac6..1d3db0a3d97 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -1060,10 +1060,10 @@ class ProcurementRule(models.Model): 'partner_id': partner.id, 'picking_type_id': self.picking_type_id.id, 'company_id': values['company_id'].id, - 'currency_id': partner.property_purchase_currency_id.id or self.env.user.company_id.currency_id.id, + 'currency_id': partner.with_context(force_company=values['company_id'].id).property_purchase_currency_id.id or self.env.user.company_id.currency_id.id, 'dest_address_id': values.get('partner_dest_id', False) and values['partner_dest_id'].id, 'origin': origin, - 'payment_term_id': partner.property_supplier_payment_term_id.id, + 'payment_term_id': partner.with_context(force_company=values['company_id'].id).property_supplier_payment_term_id.id, 'date_order': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT), 'fiscal_position_id': fpos, 'group_id': group diff --git a/addons/sale/report/report_all_channels_sales.py b/addons/sale/report/report_all_channels_sales.py index 5e1f9eca28b..753ea03d112 100644 --- a/addons/sale/report/report_all_channels_sales.py +++ b/addons/sale/report/report_all_channels_sales.py @@ -57,6 +57,7 @@ class PosSaleReport(models.Model): (cr.date_end IS NULL OR cr.date_end > COALESCE(so.date_order, now()))) LEFT JOIN product_uom u on (u.id=sol.product_uom) LEFT JOIN product_uom u2 on (u2.id=pt.uom_id) + WHERE so.state != 'cancel' """ % self.env['res.currency']._select_companies_rates() return so_str diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index 752a7a7c9fc..c9b72a4defa 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -186,4 +186,5 @@ class SaleAdvancePaymentInv(models.TransientModel): 'invoice_policy': 'order', 'property_account_income_id': self.deposit_account_id.id, 'taxes_id': [(6, 0, self.deposit_taxes_id.ids)], + 'company_id': False, } diff --git a/addons/sale_timesheet/tests/test_timesheet_revenue.py b/addons/sale_timesheet/tests/test_timesheet_revenue.py index cbd49c03dd3..bee2af72288 100644 --- a/addons/sale_timesheet/tests/test_timesheet_revenue.py +++ b/addons/sale_timesheet/tests/test_timesheet_revenue.py @@ -19,6 +19,11 @@ class TestSaleTimesheet(TestSale): # after the 6 june of current year. self.env.ref('base.rateUSDbis').unlink() + # Make sure the company is in USD + self.env.cr.execute( + "UPDATE res_company SET currency_id = %s WHERE id = %s", + [self.env.ref('base.USD').id, self.env.user.company_id.id]) + # create project self.project = self.env['project.project'].create({ 'name': 'Project for my timesheets', diff --git a/addons/test_mail/data/test_mail_data.py b/addons/test_mail/data/test_mail_data.py index 52248cb3095..ef55fb82be9 100644 --- a/addons/test_mail/data/test_mail_data.py +++ b/addons/test_mail/data/test_mail_data.py @@ -290,4 +290,145 @@ X-Attachment-Id: ii_151b51a290ed6a91 R0lGODdhAgACALMAAAAAAP///wAAAP//AP8AAP+AAAD/AAAAAAAA//8A/wAAAP+AgAAAAAAAAAAA AAAAACwAAAAAAgACAAAEA3DJFQA7 --001a11416b9e9b229a05272b7052-- -""" \ No newline at end of file +""" + +MAIL_EML_ATTACHMENT = """Subject: Re: test attac +From: Anon +To: anon@gmail.com +References: +Message-ID: +Date: Wed, 14 Mar 2018 14:26:58 +0100 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 + Thunderbird/52.6.0 +MIME-Version: 1.0 +In-Reply-To: +Content-Type: multipart/mixed; + boundary="------------A6B5FD5F68F4D73ECD739009" +Content-Language: en-US + +This is a multi-part message in MIME format. +--------------A6B5FD5F68F4D73ECD739009 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: 7bit + + + +On 14/03/18 14:20, Anon wrote: +> Some nice content +> + + +--------------A6B5FD5F68F4D73ECD739009 +Content-Type: message/rfc822; + name="original_msg.eml" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; + filename="original_msg.eml" + +Delivered-To: anon2@gmail1.openerp.com +Received: by 10.46.1.170 with SMTP id f42csp2379722lji; + Mon, 5 Mar 2018 01:19:23 -0800 (PST) +X-Google-Smtp-Source: AG47ELsYTlAcblMxfnaEENQuF+MFoac5Q07wieyw0cybq/qOX4+DmayqoQILkiWT+NiTOcnr/ACO +X-Received: by 10.28.154.213 with SMTP id c204mr7237750wme.64.1520241563503; + Mon, 05 Mar 2018 01:19:23 -0800 (PST) +ARC-Seal: i=1; a=rsa-sha256; t=1520241563; cv=none; + d=google.com; s=arc-20160816; + b=BqgMSbqmbpYW1ZtfGTVjj/654MBmabw4XadNZEaI96hDaub6N6cP8Guu3PoxscI9os + 0OLYVP1s/B+Vv9rIzulCwHyHsgnX+aTxGYepTDN6x8SA9Qeb9aQoNSVvQLryTAoGpaFr + vXhw8aPWyr28edE03TDFA/s7X65Bf6dV5zJdMiUPVqGkfYfcTHMf3nDER5vk8vQj7tve + Cfyy0h9vLU9RSEtdFwmlEkLmgT9NQ3GDf0jQ97eMXPgR2q6duCPoMcz15KlWOno53xgH + EiV7aIZ5ZMN/m+/2xt3br/ubJ5euFojWhDnHUZoaqd08TCSQPd4fFCCx75MjDeCnwYMn + iKSg== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=content-language:mime-version:user-agent:date:message-id:subject + :from:to:dkim-signature:arc-authentication-results; + bh=/UIFqhjCCbwBLsI4w7YY98QH6G/wxe+2W4bbMDCskjM=; + b=Wv5jt+usnSgWI96GaZWUN8/VKl1drueDpU/4gkyX/iK4d6S4CuSDjwYAc3guz/TjeW + GoKCqT30IGZoStpXQbuLry7ezXNK+Fp8MJKN2n/x5ClJWHxIsxIGlP2QC3TO8RI0P5o0 + GXG9izW93q1ubkdPJFt3unSjjwSYf5XVQAZQtRm9xKjqA+lbtFbsnbjJ4wgYBURnD8ma + Qxb2xsxXDelaZvtdlzHRDn5SEkbqhcCclEYw6oRLpVQFZeYtPxcCleVybtj2owJxdaLp + 7wXuo/gpYe6E2cPuS2opei8AzjEhYTNzlYXTPvaoxCCTTjfGTaPv22TeRDehuIXngSEl + Nmmw== +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@odoo.com header.s=mail header.b=MCzhjB9b; + spf=pass (google.com: domain of soup@odoo.com designates 149.202.180.44 as permitted sender) smtp.mailfrom=soup@odoo.com; + dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=odoo.com +Return-Path: +Received: from mail2.odoo.com (mail2.odoo.com. [149.202.180.44]) + by mx.google.com with ESMTPS id y4si4279200wmy.148.2018.03.05.01.19.22 + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Mon, 05 Mar 2018 01:19:23 -0800 (PST) +Received-SPF: pass (google.com: domain of soup@odoo.com designates 149.202.180.44 as permitted sender) client-ip=149.202.180.44; +Authentication-Results: mx.google.com; + dkim=pass header.i=@odoo.com header.s=mail header.b=MCzhjB9b; + spf=pass (google.com: domain of soup@odoo.com designates 149.202.180.44 as permitted sender) smtp.mailfrom=soup@odoo.com; + dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=odoo.com +Received: from [10.10.31.24] (unknown [91.183.114.50]) + (Authenticated sender: soup) + by mail2.odoo.com (Postfix) with ESMTPSA id 7B571A4085 + for ; Mon, 5 Mar 2018 10:19:21 +0100 (CET) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=odoo.com; s=mail; + t=1520241562; bh=L2r7Sp/vjogIdM1k8H9zDGDjnhKolsTTLLjndnFC4Jc=; + h=To:From:Subject:Date:From; + b=MCzhjB9bnsrJ3uKjq+GjujFxmtrq3fc7Vv7Vg2C72EPKnkxgqy6yPjWKtXbBlaiT3 + YjKI24aiSQlOeOPQiqFgiDzeqqemNDp+CRuhoYz1Vbz+ESRaHtkWRLb7ZjvohS2k7e + RTq7tUxY2nUL2YrNHV7DFYtJVBwiTuyLP6eAiJdE= +To: what@odoo.com +From: Soup +Subject: =?UTF-8?Q?Soupe_du_jour_:_Pois_cass=c3=a9s?= +Message-ID: +Date: Mon, 5 Mar 2018 10:19:21 +0100 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 + Thunderbird/52.6.0 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="------------1F2D18B1129FC2F0B9EECF50" +Content-Language: en-US +X-Spam-Status: No, score=-1.2 required=5.0 tests=ALL_TRUSTED,BAYES_00, + HTML_IMAGE_ONLY_08,HTML_MESSAGE,T_REMOTE_IMAGE autolearn=no + autolearn_force=no version=3.4.0 +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail2.odoo.com + +This is a multi-part message in MIME format. +--------------1F2D18B1129FC2F0B9EECF50 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: 8bit + +Résultat de recherche d'images pour "dessin la princesse au petit pois" + +-- +Soup + +Odoo S.A. +Chaussée de Namur, 40 +B-1367 Grand Rosière +Web: http://www.odoo.com + + +--------------1F2D18B1129FC2F0B9EECF50 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: 8bit + + + + + + + +

Résultat de recherche d'images pour "dessin la
+        princesse au petit pois"

+
--
+Soup
+
+Odoo S.A.
+Chaussée de Namur, 40
+B-1367 Grand Rosière
+Web: http://www.odoo.com 
+ + + +--------------1F2D18B1129FC2F0B9EECF50-- + +--------------A6B5FD5F68F4D73ECD739009--""" diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index ccf5fb64423..f07a21bcaf6 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -7,7 +7,7 @@ from email.utils import formataddr from odoo.addons.test_mail.data.test_mail_data import \ MAIL_TEMPLATE, MAIL_TEMPLATE_PLAINTEXT, MAIL_MULTIPART_MIXED, MAIL_MULTIPART_MIXED_TWO, \ - MAIL_MULTIPART_IMAGE, MAIL_SINGLE_BINARY + MAIL_MULTIPART_IMAGE, MAIL_SINGLE_BINARY, MAIL_EML_ATTACHMENT from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails from odoo.tools import mute_logger @@ -78,6 +78,12 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): 'message_id': '<123456-openerp-%s-mail.test.simple@%s>' % (cls.test_record.id, socket.gethostname()), }) + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_parse_eml(self): + """ Test that the parsing of mail with embedded emails as eml(msg) which generates empty attachments, can be processed. + """ + self.env['mail.thread'].message_process('mail.channel', MAIL_EML_ATTACHMENT) + @mute_logger('odoo.addons.mail.models.mail_thread') def test_message_process_cid(self): record = self.format_and_process(MAIL_MULTIPART_IMAGE, to='groups@example.com') diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js index dc97da37365..256d20f9d5f 100644 --- a/addons/web_editor/static/src/js/editor/summernote.js +++ b/addons/web_editor/static/src/js/editor/summernote.js @@ -1975,7 +1975,13 @@ eventHandler.modules.toolbar.button.updateRecentColor = function (elBtn, sEvent, }; $(document).on('click keyup', function () { - var $popover = $((range.create()||{}).sc).closest('[contenteditable]'); + var current_range = {}; + try { + current_range = range.create() || {}; + } catch (e) { + // if range is on Restricted element ignore error + } + var $popover = $(current_range.sc).closest('[contenteditable]'); var popover_history = ($popover.data()||{}).NoteHistory; if (!popover_history || popover_history === history) return; var editor = $popover.parent('.note-editor'); diff --git a/addons/web_editor/static/src/js/editor/transcoder.js b/addons/web_editor/static/src/js/editor/transcoder.js index 4fa30978f84..fb3e69eda29 100644 --- a/addons/web_editor/static/src/js/editor/transcoder.js +++ b/addons/web_editor/static/src/js/editor/transcoder.js @@ -227,6 +227,26 @@ function imgToFont($editable) { }); } +/* + * Utility function to apply function over descendants elements + * + * This is needed until the following issue of jQuery is solved: + * https://github.com./jquery/sizzle/issues/403 + * + * @param {Element} node The root Element node + * @param {Function} func The function applied over descendants + */ +function applyOverDescendants(node, func) { + node = node.firstChild; + while (node) { + if (node.nodeType === 1) { + func(node); + applyOverDescendants(node, func); + } + node = node.nextSibling; + } +} + /** * Converts css style to inline style (leave the classes on elements but forces * the style they give as inline style). @@ -237,9 +257,9 @@ function classToStyle($editable) { if (!rulesCache.length) { getMatchedCSSRules($editable[0]); } - $editable.find('*').each(function () { - var $target = $(this); - var css = getMatchedCSSRules(this); + applyOverDescendants($editable[0], function (node) { + var $target = $(node); + var css = getMatchedCSSRules(node); var style = $target.attr('style') || ''; _.each(css, function (v,k) { if (!(new RegExp('(^|;)\s*' + k).test(style))) { @@ -252,12 +272,12 @@ function classToStyle($editable) { $target.attr('style', style); } // Apple Mail - if (this.nodeName === 'TD' && !this.childNodes.length) { - this.innerHTML = ' '; + if (node.nodeName === 'TD' && !node.childNodes.length) { + node.innerHTML = ' '; } // Outlook - if (this.nodeName === 'A' && $target.hasClass('btn') && !$target.children().length) { + if (node.nodeName === 'A' && $target.hasClass('btn') && !$target.children().length) { var $hack = $('
'); $hack.find('td') .attr('height', $target.outerHeight()) @@ -269,7 +289,7 @@ function classToStyle($editable) { $target.after($hack); $target.appendTo($hack.find('td')); // the space add a line when it's a table but it's invisible when it's a link - var node = $hack[0].previousSibling; + node = $hack[0].previousSibling; if (node && node.nodeType === Node.TEXT_NODE && !node.textContent.match(/\S/)) { $(node).remove(); } @@ -297,9 +317,9 @@ function styleToClass($editable) { var $c = $('').appendTo(document.body); - $editable.find('*').each(function () { - var $target = $(this); - var css = getMatchedCSSRules(this); + applyOverDescendants($editable[0], function (node) { + var $target = $(node); + var css = getMatchedCSSRules(node); var style = ''; _.each(css, function (v,k) { if (!(new RegExp('(^|;)\s*' + k).test(style))) { diff --git a/addons/website_sale/models/res_partner.py b/addons/website_sale/models/res_partner.py index 6755a4b6a54..77fc633c9c8 100644 --- a/addons/website_sale/models/res_partner.py +++ b/addons/website_sale/models/res_partner.py @@ -7,4 +7,4 @@ from odoo import models, fields class ResPartner(models.Model): _inherit = 'res.partner' - last_website_so_id = fields.Many2one('sale.order', string='Last Online Sales Order') + last_website_so_id = fields.Many2one('sale.order', string='Last Online Sales Order', copy=False) diff --git a/odoo/addons/base/tests/test_mail.py b/odoo/addons/base/tests/test_mail.py index c0f437be385..5693906c092 100644 --- a/odoo/addons/base/tests/test_mail.py +++ b/odoo/addons/base/tests/test_mail.py @@ -116,7 +116,7 @@ class TestSanitizer(unittest.TestCase): test_data = [ ( 'Coin coin ', - ['background-color: red', 'Coin coin'], + ['background-color:red', 'Coin coin'], ['position', 'top', 'left'] ), ( """
youplaboum
""", - ['font-size: 30px', 'youplaboum'], + ['font-size:30px', 'youplaboum'], ['some-property', 'top', 'cheval'] ), ( 'Coincoin', diff --git a/odoo/addons/base/tests/test_mail_examples.py b/odoo/addons/base/tests/test_mail_examples.py index 4f3b5b48300..032d321ff06 100644 --- a/odoo/addons/base/tests/test_mail_examples.py +++ b/odoo/addons/base/tests/test_mail_examples.py @@ -510,7 +510,7 @@ REMOVE_CLASS = u""" """ REMOVE_CLASS_IN = [ - u'
', + u'
', u'An error occured in a modal and I will send you back the html to try opening one on your end'] REMOVE_CLASS_OUT = [ u'