From dc1b8a5a51dfabcdefcb5cbb8b7d5d141bb00e53 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 25 Apr 2016 12:33:19 +0200 Subject: [PATCH 01/68] [FIX] res_company: some information missed on company creation On the `res.company` model, the fields `name`, `phone`, `email`, `website`, `vat` are related field on the `partner_id` of the company. When creating a new company, the partner associated to the company is created automatically, it's handled in the overrided `create` method of the model, but it forgots the values `phone`, `email`, `website`, `vat` at the moment the partner is being created. opw-675526 --- openerp/addons/base/res/res_company.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 3b8464e20b6..71995487cf1 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -276,7 +276,16 @@ class res_company(osv.osv): self.cache_restart(cr) return super(res_company, self).create(cr, uid, vals, context=context) obj_partner = self.pool.get('res.partner') - partner_id = obj_partner.create(cr, uid, {'name': vals['name'], 'is_company':True, 'image': vals.get('logo', False), 'customer': False}, context=context) + partner_id = obj_partner.create(cr, uid, { + 'name': vals['name'], + 'is_company': True, + 'image': vals.get('logo', False), + 'customer': False, + 'email': vals.get('email'), + 'phone': vals.get('phone'), + 'website': vals.get('website'), + 'vat': vals.get('vat'), + }, context=context) vals.update({'partner_id': partner_id}) self.cache_restart(cr) company_id = super(res_company, self).create(cr, uid, vals, context=context) From e680f29560ac20133c7af0c6364c6ef494662eac Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Mon, 25 Apr 2016 14:11:47 +0200 Subject: [PATCH 02/68] [FIX] account, sale: modify invoice When a user validates an invoice linked to a SO, he might want to modify it afterwards thanks to the 'Modify' option in the refund wizard. This will create a refund, reconcile and create a draft invoice. The issue is that the draft invoice is not linked with the SO. The fix is to link, in this specific case only, the draft invoice to the SO. At the same time, we have to make sure to: - unlink the first invoice (to prevent counting the quantity as invoiced in the SO) - keep track of the first invoice/refund in the invoice list of the SO opw-673446 --- addons/account/wizard/account_invoice_refund.py | 2 +- addons/sale/sale.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/addons/account/wizard/account_invoice_refund.py b/addons/account/wizard/account_invoice_refund.py index 226b3e711f8..638b0e1fc1e 100644 --- a/addons/account/wizard/account_invoice_refund.py +++ b/addons/account/wizard/account_invoice_refund.py @@ -87,7 +87,7 @@ class AccountInvoiceRefund(models.TransientModel): invoice = invoice[0] del invoice['id'] invoice_lines = inv_line_obj.browse(invoice['invoice_line_ids']) - invoice_lines = inv_obj._refund_cleanup_lines(invoice_lines) + invoice_lines = inv_obj.with_context(mode='modify')._refund_cleanup_lines(invoice_lines) tax_lines = inv_tax_obj.browse(invoice['tax_line_ids']) tax_lines = inv_obj._refund_cleanup_lines(tax_lines) invoice.update({ diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 02b00c9680c..3bea2419718 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -52,6 +52,9 @@ class SaleOrder(models.Model): """ for order in self: invoice_ids = order.order_line.mapped('invoice_lines').mapped('invoice_id') + # Search for invoices which have been 'cancelled' (filter_refund = 'modify' in + # 'account.invoice.refund') + invoice_ids |= invoice_ids.search([('origin', 'like', order.name)]) # Search for refunds as well refund_ids = self.env['account.invoice'].browse() if invoice_ids: @@ -835,6 +838,16 @@ class AccountInvoice(models.Model): order.message_post(body=_("Invoice %s paid") % (name)) return res + @api.model + def _refund_cleanup_lines(self, lines): + result = super(AccountInvoice, self)._refund_cleanup_lines(lines) + if self.env.context.get('mode') == 'modify': + for i in xrange(0, len(lines)): + for name, field in lines[i]._fields.iteritems(): + if name == 'sale_line_ids': + result[i][2][name] = [(6, 0, lines[i][name].ids)] + lines[i][name] = False + return result class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' From 61c808b77425c35f9e6f9774ee88ae7e8a2c995d Mon Sep 17 00:00:00 2001 From: Ludwik Trammer Date: Mon, 25 Apr 2016 14:54:18 +0200 Subject: [PATCH 03/68] [FIX] web: Allow for translation of a login error message Closes #11815 --- addons/web/controllers/main.py | 2 +- addons/web/i18n/web.pot | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 7413159c9a3..038a317224b 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -510,7 +510,7 @@ class Home(http.Controller): if uid is not False: return http.redirect_with_hash(redirect) request.uid = old_uid - values['error'] = "Wrong login/password" + values['error'] = _("Wrong login/password") if request.env.ref('web.login', False): return request.render('web.login', values) else: diff --git a/addons/web/i18n/web.pot b/addons/web/i18n/web.pot index f4855962d9a..6522ed569ce 100644 --- a/addons/web/i18n/web.pot +++ b/addons/web/i18n/web.pot @@ -2661,6 +2661,12 @@ msgstr "" msgid "Wk" msgstr "" +#. module: web +#: code:addons/web/controllers/main.py:513 +#, python-format +msgid "Wrong login/password" +msgstr "" + #. module: web #. openerp-web #: code:addons/web/static/src/xml/base.xml:565 From e24888205375ecf6d6ad2832ce7cbaee0c5edf89 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Mon, 25 Apr 2016 16:26:04 +0200 Subject: [PATCH 04/68] [FIX] base: fetch mimetype on ir.attachment for binary fields --- openerp/addons/base/ir/ir_http.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py index 72e66e24c33..5148b11c8d8 100644 --- a/openerp/addons/base/ir/ir_http.py +++ b/openerp/addons/base/ir/ir_http.py @@ -300,6 +300,10 @@ class ir_http(osv.AbstractModel): mimetype = obj.mimetype elif filename: mimetype = mimetypes.guess_type(filename)[0] + elif getattr(env[model]._fields[field], 'attachment', False): + # for binary fields, fetch the ir_attachement for mimetype check + attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) + mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] if not mimetype: mimetype = default_mimetype headers.append(('Content-Type', mimetype)) From dde1404cb9ce538cc1216c9256f0f5c1e74ecc06 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 25 Apr 2016 18:00:01 +0200 Subject: [PATCH 05/68] [FIX] sale: Teams dashboard, sales to invoice count From 9.0, a sales order to invoice is no longer a sales order in the state `manual`, but with the Invoice Status "to invoice". Before this revision, the sales order to invoice were simply not counted at all, and this count always displayed 0. opw-675919 --- addons/sale/sales_team.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/sales_team.py b/addons/sale/sales_team.py index c4a593cf11d..309419eb97f 100644 --- a/addons/sale/sales_team.py +++ b/addons/sale/sales_team.py @@ -18,7 +18,7 @@ class crm_team(osv.Model): res = dict.fromkeys(ids, 0) domain = [ ('team_id', 'in', ids), - ('state', '=', 'manual'), + ('invoice_status', '=', 'to invoice'), ] amounts = obj.read_group(cr, uid, domain, ['amount_total', 'team_id'], ['team_id'], context=context) for rec in amounts: From e1ed2c6ddc6750a2090ee37badfaeccadd765b9b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 25 Apr 2016 14:01:01 +0200 Subject: [PATCH 06/68] [FIX] mail: visibility rules for channel notifications Avoid raising an access denied error for messages that the user has indeed be notified about. The issue arose when a message posted on a document inaccessible to the user was notified to one of the channels the user is subscribed to. The access control logic on messages relies on 2 heuristics to grant read access to a message: a. either the user was notified about the messages, by being a follower of the document, or a subscriber of a channel following the document (in that case the user can see the message but not the document) b. or the user has read access to the document on which the message is posted (in that case the user can see both the message and the document) Case `a.` sometimes fail to match when a message got notified to several channels including one the user was not subscribed to. Depending on the order of the returned rows in the SQL query, the "foreign" channels could shadow the channels of the user, making `a.` a non-match. If case `b.` did not match either, the user would have the `read` access denied, even though the message was visible by the `search()` method. The fix explicitly makes case `a.` match if the user was notified in *at least* one channel. This was not done through a change of the SQL query ORDER, for readability reasons. --- addons/mail/models/mail_message.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index fe7d6d88448..f86ba64ce7e 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -741,7 +741,13 @@ class Message(models.Model): ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = (%%s) WHERE m.id = ANY (%%s)""" % self._table, (self.env.user.partner_id.id, self.env.user.partner_id.id, self.ids,)) for mid, rmod, rid, author_id, parent_id, partner_id, channel_id in self._cr.fetchall(): - message_values[mid] = {'model': rmod, 'res_id': rid, 'author_id': author_id, 'parent_id': parent_id, 'partner_id': partner_id, 'channel_id': channel_id} + message_values[mid] = { + 'model': rmod, + 'res_id': rid, + 'author_id': author_id, + 'parent_id': parent_id, + 'notified': any((message_values[mid].get('notified'), partner_id, channel_id)) + } else: self._cr.execute("""SELECT DISTINCT id, model, res_id, author_id, parent_id FROM "%s" WHERE id = ANY (%%s)""" % self._table, (self.ids,)) for mid, rmod, rid, author_id, parent_id in self._cr.fetchall(): @@ -780,7 +786,7 @@ class Message(models.Model): other_ids = set(self.ids).difference(set(author_ids), set(notified_ids)) model_record_ids = _generate_model_record_ids(message_values, other_ids) if operation in ['read', 'write']: - notified_ids = [mid for mid, message in message_values.iteritems() if message.get('partner_id') or message.get('channel_id')] + notified_ids = [mid for mid, message in message_values.iteritems() if message.get('notified')] elif operation == 'create': for doc_model, doc_ids in model_record_ids.items(): followers = self.env['mail.followers'].sudo().search([ From ccd7a157092c9b9d7708c14b9d263d47a92f233b Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Mon, 25 Apr 2016 18:28:01 +0200 Subject: [PATCH 07/68] [FIX] base: fixes previous fix In fix e248882, the previous elif statement prevented the execution of the fix code. This fix fixes the fix. --- openerp/addons/base/ir/ir_http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py index 5148b11c8d8..e04bd270eea 100644 --- a/openerp/addons/base/ir/ir_http.py +++ b/openerp/addons/base/ir/ir_http.py @@ -300,7 +300,7 @@ class ir_http(osv.AbstractModel): mimetype = obj.mimetype elif filename: mimetype = mimetypes.guess_type(filename)[0] - elif getattr(env[model]._fields[field], 'attachment', False): + if not mimetype and getattr(env[model]._fields[field], 'attachment', False): # for binary fields, fetch the ir_attachement for mimetype check attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] From a84342441d80ac1da03417ca0a40ab2fb225b9b2 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Tue, 26 Apr 2016 09:35:10 +0200 Subject: [PATCH 08/68] [FIX] hr_recruitment: no create on ir_attachment action The "Resumes and Letters" action simply displays ir_attachments linked to hr_applicant objects; but there is no default_res_model in the context so no ir_attachment you create is actually displayed in the kanban view. Since the goal of this action is simply to display attachments linked to applicants, it makes more sense to disable the create button and to force people to upload resumes and cover letters through the applicant record. --- addons/hr_recruitment/views/hr_recruitment_views.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/hr_recruitment/views/hr_recruitment_views.xml b/addons/hr_recruitment/views/hr_recruitment_views.xml index 4926c8f3003..ec8b246ff62 100644 --- a/addons/hr_recruitment/views/hr_recruitment_views.xml +++ b/addons/hr_recruitment/views/hr_recruitment_views.xml @@ -559,6 +559,7 @@ kanban,tree,form [('res_model','=','hr.applicant')] + {'create': False}

Search through resumes and motivation letters. From f5eae92f12a86d0c63a7e9b30d9afe9f852c7bda Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 26 Apr 2016 10:14:56 +0200 Subject: [PATCH 09/68] [FIX] website_sale: log if no pricelist The pricelist field is not a mandatory field on the partner. A default value is usually defined for any new partner created. However, if the pricelist is manually removed from the partner, errors (tracebacks) will occur in the eCommerce when no pricelist is found. We cannot make the field mandatory, as it could potentially break the workflow of some users which are not using eCommerce. Therefore, we simply log an error message to help debugging. opw-673453 --- addons/website_sale/controllers/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 729b99fcbec..0ae469c98c7 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import logging import werkzeug from openerp import SUPERUSER_ID @@ -11,6 +12,8 @@ from openerp.addons.web.controllers.main import login_redirect PPG = 20 # Products Per Page PPR = 4 # Products Per Row +_logger = logging.getLogger(__name__) + class table_compute(object): def __init__(self): self.table = {} @@ -111,6 +114,8 @@ def get_pricelist(): else: partner = pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id pricelist = partner.property_product_pricelist + if not pricelist: + _logger.error('Fail to find pricelist for partner "%s" (id %s)', partner.name, partner.id) return pricelist class website_sale(http.Controller): From d812175390423f2b265ddd8957b887ed6df99ce8 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 14 Apr 2016 16:16:56 +0200 Subject: [PATCH 10/68] [FIX] account_asset: asset_create When creating assets from invoice lines, the system must check that assets have not already been created for the related invoice. If assets already exist then these assets have to be removed. Used case: - In the purchase journal, tick "allow canceling entries" - On a supplier invoice line, set an asset category - validate the invoice - cancel the invoice - set to draft - validate the invoice Before the fix: the asset is created twice. After the fix: the asset is created once. opw:674674 --- addons/account_asset/account_asset_invoice.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py index 9212bc2f73c..aba583aea16 100644 --- a/addons/account_asset/account_asset_invoice.py +++ b/addons/account_asset/account_asset_invoice.py @@ -47,11 +47,12 @@ class account_invoice_line(osv.osv): def asset_create(self, cr, uid, lines, context=None): context = context or {} asset_obj = self.pool.get('account.asset.asset') + asset_ids = [] for line in lines: if line.invoice_id.number: - if asset_obj.search(cr, SUPERUSER_ID, [('code', '=', line.invoice_id.number)], context=context): - raise osv.except_osv(_('Warning!'), _('You already have assets with the reference %s.\nPlease delete these assets before creating new ones for this invoice.') % (line.invoice_id.number)) - + #FORWARDPORT UP TO SAAS-6 + asset_ids += asset_obj.search(cr, SUPERUSER_ID, [('code', '=', line.invoice_id.number), ('company_id', '=', line.company_id.id)], context=context) + asset_obj.write(cr, SUPERUSER_ID, asset_ids, {'active': False}) for line in lines: if line.asset_category_id: vals = { From 9d14230d74ecc4ebf07d8e9f264bfbe066c17ff0 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 25 Apr 2016 17:11:34 +0200 Subject: [PATCH 11/68] [FIX] account_asset: asset_create When creating assets from invoice lines, the system must check that assets have not already been created for the related invoice. If assets already exist then these assets have to be removed. Used case: - In the purchase journal, tick "allow canceling entries" - On a supplier invoice line, set an asset category - validate the invoice - cancel the invoice - set to draft - validate the invoice Before the fix: the asset is created twice. After the fix: the asset is created once. opw:674674 --- addons/account_asset/account_asset_invoice.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py index 88027ca8125..76283257aae 100644 --- a/addons/account_asset/account_asset_invoice.py +++ b/addons/account_asset/account_asset_invoice.py @@ -17,8 +17,9 @@ class AccountInvoice(models.Model): result = super(AccountInvoice, self).action_move_create() for inv in self: if inv.number: - if self.env['account.asset.asset'].sudo().search([('code', '=', inv.number)]): - raise Warning(_('You already have assets with the reference %s.\nPlease delete these assets before creating new ones for this invoice.') % (inv.number,)) + asset_ids = self.env['account.asset.asset'].sudo().search([('invoice_id', '=', inv.id), ('company_id', '=', inv.company_id.id)]) + if asset_ids: + asset_ids .write({'active': False}) inv.invoice_line_ids.asset_create() return result From 6e3389ca73f2bbf97a9b706d8fc5d0af21f95006 Mon Sep 17 00:00:00 2001 From: David Monjoie Date: Tue, 26 Apr 2016 11:16:37 +0200 Subject: [PATCH 12/68] [FIX] website_form: prevent users from crazy clicking If the feedback of a form is too slow, people might be tempted to click a second time, trigerring a second request. If, after that, the result has not been received yet, the user might be tempted to click a lot of time because he is angry at such slowness. This behavior would trigger a record creation each time the user clicked the submit button. This fix disables the button once it has been clicked once, and re-enable it if the record could not be created, which means that there was an error in the input and the user needs to change the values and try again. The button has been changed to a span to avoid the default browser behavior to post the form when no function is bound on the send button. --- addons/website_crm/views/website_crm.xml | 2 +- addons/website_form/static/src/js/website_form.js | 5 +++++ addons/website_hr_recruitment/views/templates.xml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/website_crm/views/website_crm.xml b/addons/website_crm/views/website_crm.xml index db2086b07a1..fc4208a1e7e 100644 --- a/addons/website_crm/views/website_crm.xml +++ b/addons/website_crm/views/website_crm.xml @@ -44,7 +44,7 @@

- + Send
diff --git a/addons/website_form/static/src/js/website_form.js b/addons/website_form/static/src/js/website_form.js index cea891ef135..ad5dcaa5cb7 100644 --- a/addons/website_form/static/src/js/website_form.js +++ b/addons/website_form/static/src/js/website_form.js @@ -47,6 +47,7 @@ odoo.define('website_form.animation', function (require) { send: function(e) { e.preventDefault(); // Prevent the default submit behavior + this.$target.find('.o_website_form_send').off(); // Prevent users from crazy clicking var self = this; @@ -211,6 +212,10 @@ odoo.define('website_form.animation', function (require) { }, update_status: function(status) { + var self = this; + if (status != 'success') { // Restore send button behavior if result is an error + this.$target.find('.o_website_form_send').on('click',function(e) {self.send(e);}); + } this.$target.find('#o_website_form_result').replaceWith(qweb.render("website_form.status_" + status)) }, }); diff --git a/addons/website_hr_recruitment/views/templates.xml b/addons/website_hr_recruitment/views/templates.xml index 3ac6736a7e2..38643a7479e 100644 --- a/addons/website_hr_recruitment/views/templates.xml +++ b/addons/website_hr_recruitment/views/templates.xml @@ -195,7 +195,7 @@
- + Submit
From 58a5b5e453e39f1e334f4d7d4a89c9c4e3a790c2 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 26 Apr 2016 11:30:55 +0200 Subject: [PATCH 13/68] [FIX] account_asset: Typo error --- addons/account_asset/account_asset_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py index 76283257aae..8e8187b93bf 100644 --- a/addons/account_asset/account_asset_invoice.py +++ b/addons/account_asset/account_asset_invoice.py @@ -19,7 +19,7 @@ class AccountInvoice(models.Model): if inv.number: asset_ids = self.env['account.asset.asset'].sudo().search([('invoice_id', '=', inv.id), ('company_id', '=', inv.company_id.id)]) if asset_ids: - asset_ids .write({'active': False}) + asset_ids.write({'active': False}) inv.invoice_line_ids.asset_create() return result From 02fd74a3faa248483bdc6b4ca9fd0b4dc05557bc Mon Sep 17 00:00:00 2001 From: David Monjoie Date: Tue, 26 Apr 2016 11:16:37 +0200 Subject: [PATCH 14/68] [FIX] website_form: prevent users from crazy clicking If the feedback of a form is too slow, people might be tempted to click a second time, trigerring a second request. If, after that, the result has not been received yet, the user might be tempted to click a lot of time because he is angry at such slowness. This behavior would trigger a record creation each time the user clicked the submit button. This fix disables the button once it has been clicked once, and re-enable it if the record could not be created, which means that there was an error in the input and the user needs to change the values and try again. The button has been changed to a span to avoid the default browser behavior to post the form when no function is bound on the send button. --- addons/website_crm/views/website_crm.xml | 2 +- addons/website_form/static/src/js/website_form.js | 5 +++++ addons/website_hr_recruitment/views/templates.xml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/website_crm/views/website_crm.xml b/addons/website_crm/views/website_crm.xml index db2086b07a1..fc4208a1e7e 100644 --- a/addons/website_crm/views/website_crm.xml +++ b/addons/website_crm/views/website_crm.xml @@ -44,7 +44,7 @@
- + Send
diff --git a/addons/website_form/static/src/js/website_form.js b/addons/website_form/static/src/js/website_form.js index cea891ef135..ad5dcaa5cb7 100644 --- a/addons/website_form/static/src/js/website_form.js +++ b/addons/website_form/static/src/js/website_form.js @@ -47,6 +47,7 @@ odoo.define('website_form.animation', function (require) { send: function(e) { e.preventDefault(); // Prevent the default submit behavior + this.$target.find('.o_website_form_send').off(); // Prevent users from crazy clicking var self = this; @@ -211,6 +212,10 @@ odoo.define('website_form.animation', function (require) { }, update_status: function(status) { + var self = this; + if (status != 'success') { // Restore send button behavior if result is an error + this.$target.find('.o_website_form_send').on('click',function(e) {self.send(e);}); + } this.$target.find('#o_website_form_result').replaceWith(qweb.render("website_form.status_" + status)) }, }); diff --git a/addons/website_hr_recruitment/views/templates.xml b/addons/website_hr_recruitment/views/templates.xml index 3ac6736a7e2..38643a7479e 100644 --- a/addons/website_hr_recruitment/views/templates.xml +++ b/addons/website_hr_recruitment/views/templates.xml @@ -195,7 +195,7 @@
- + Submit
From 3108a49ab20b721669c666b64140d5a26d90aeae Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 25 Apr 2016 15:07:40 +0200 Subject: [PATCH 15/68] [FIX] crm_claim: access rights for portal user The portal user is not allowed to read the crm.team model. opw:673480 --- addons/sales_team/sales_team.py | 3 ++- addons/website_project_issue/security/ir.model.access.csv | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/sales_team/sales_team.py b/addons/sales_team/sales_team.py index 93cdee60ed5..62b2163a888 100644 --- a/addons/sales_team/sales_team.py +++ b/addons/sales_team/sales_team.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from openerp import SUPERUSER_ID from openerp.osv import fields, osv @@ -16,7 +17,7 @@ class crm_team(osv.Model): context = {} if user_id is None: user_id = uid - team_ids = self.search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', 'in', user_id)], limit=1, context=context) + team_ids = self.search(cr, SUPERUSER_ID, ['|', ('user_id', '=', user_id), ('member_ids', 'in', user_id)], limit=1, context=context) team_id = team_ids[0] if team_ids else False if not team_id and context.get('default_team_id'): team_id = context['default_team_id'] diff --git a/addons/website_project_issue/security/ir.model.access.csv b/addons/website_project_issue/security/ir.model.access.csv index e55c4c4a1cf..d84e0831aba 100644 --- a/addons/website_project_issue/security/ir.model.access.csv +++ b/addons/website_project_issue/security/ir.model.access.csv @@ -1,3 +1,2 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_issues,project_issue,project_issue.model_project_issue,base.group_portal,1,0,0,0 -access_case_section,crm_team,sales_team.model_crm_team,base.group_portal,1,0,0,0 From 571d97e62e9ad862e829fa3341515260dacbe897 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 25 Apr 2016 11:19:24 +0200 Subject: [PATCH 16/68] [FIX] res: Creating a partner with an invoice contact When creating a partner with company_type='person' and with an invoice adress, the created partner must stay a person. Now a partner which is not a comany can have an invoice address. Fixes #11730 opw:675322 --- openerp/addons/base/res/res_partner.py | 2 -- openerp/addons/base/tests/test_base.py | 1 - 2 files changed, 3 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d3ed58a76dd..b13ef071bc9 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -471,8 +471,6 @@ class res_partner(osv.Model, format_address): any(partner[f] for f in address_fields) and not any(parent[f] for f in address_fields): addr_vals = self._update_fields_values(cr, uid, partner, address_fields, context=context) parent.update_address(addr_vals) - if not parent.is_company: - parent.write({'is_company': True}) def _clean_website(self, website): (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(website) diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 11351a80517..44454f9c3d3 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -124,7 +124,6 @@ class test_base(common.TransactionCase): self.assertEquals(p1.type, 'contact', 'Default type must be "contact", not the copied parent type') ironshield.refresh() self.assertEqual(ironshield.street, p1.street, 'Address fields should be copied to company') - self.assertTrue(ironshield.is_company, 'Company flag should be turned on after first contact creation') def test_40_res_partner_address_getc(self): """ Test address_get address resolution mechanism: it should first go down through descendants, From 2dfedb5b67e600b4874aea30f997b25c22c0dafa Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 26 Apr 2016 13:40:00 +0200 Subject: [PATCH 17/68] [FIX] purchase: delete unnecessary PO line In v8.0, when a procurement is cancelled and the quantity remaining on the PO line is zero, the line is deleted. It was not the case anymore after the Purchase refactoring. opw-675493 --- addons/purchase/purchase.py | 8 +++++--- .../stock_dropshipping/test/cancellation_propagated.yml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 0e7c8be4dde..a5932311c29 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -607,7 +607,7 @@ class PurchaseOrderLine(models.Model): raise UserError(_('Cannot delete a purchase order line which is in state \'%s\'.') %(line.state,)) for proc in line.procurement_ids: proc.message_post(body=_('Purchase order line deleted.')) - line.procurement_ids.write({'state': 'exception'}) + line.procurement_ids.filtered(lambda r: r.state != 'cancel').write({'state': 'exception'}) return super(PurchaseOrderLine, self).unlink() @api.model @@ -750,8 +750,10 @@ class ProcurementOrder(models.Model): if seller and seller.product_uom != procurement.purchase_line_id.product_uom: price_unit = self.env['product.uom']._compute_price(seller.product_uom.id, price_unit, to_uom_id=procurement.purchase_line_id.product_uom.id) - procurement.purchase_line_id.product_qty = product_qty - procurement.purchase_line_id.price_unit = price_unit + procurement.purchase_line_id.product_qty = product_qty + procurement.purchase_line_id.price_unit = price_unit + else: + procurement.purchase_line_id.unlink() return result diff --git a/addons/stock_dropshipping/test/cancellation_propagated.yml b/addons/stock_dropshipping/test/cancellation_propagated.yml index 44e5ff34e6f..64eef9143f9 100644 --- a/addons/stock_dropshipping/test/cancellation_propagated.yml +++ b/addons/stock_dropshipping/test/cancellation_propagated.yml @@ -101,7 +101,7 @@ # Cancel the Sales Order 1 self.cancel(cr, uid, [so1.order_line[0].procurement_ids[0].id], context=context) assert so1.order_line[0].procurement_ids[0].state == u'cancel', 'Procurement 1 should be cancelled !' - assert purchase_line.product_qty == 0.0, 'The product quantity of the first order line should be 5 and not %s' % (purchase_line.product_qty,) + assert len(purchase_ids.order_line) == 0, 'The PO line should have been unlinked!' # Check that all procurements related are cancelled for procu in procu_ids: From 7e51d98553bfd910e8dabbcd890857b4bf1f4cd0 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 26 Apr 2016 14:55:41 +0200 Subject: [PATCH 18/68] [FIX] calendar: correct search on mail.message and ir.attachment Handle the case of immutable (tuple) domain leafs. --- addons/calendar/calendar.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/calendar/calendar.py b/addons/calendar/calendar.py index 427f515ffd0..5da9104b6a8 100644 --- a/addons/calendar/calendar.py +++ b/addons/calendar/calendar.py @@ -1759,9 +1759,10 @@ class mail_message(osv.Model): ''' convert the search on real ids in the case it was asked on virtual ids, then call super() ''' + args = list(args) for index in range(len(args)): if args[index][0] == "res_id" and isinstance(args[index][2], basestring): - args[index][2] = get_real_ids(args[index][2]) + args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2])) return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) def _find_allowed_model_wise(self, cr, uid, doc_model, doc_dict, context=None): @@ -1781,9 +1782,10 @@ class ir_attachment(osv.Model): ''' convert the search on real ids in the case it was asked on virtual ids, then call super() ''' + args = list(args) for index in range(len(args)): if args[index][0] == "res_id" and isinstance(args[index][2], basestring): - args[index][2] = get_real_ids(args[index][2]) + args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2])) return super(ir_attachment, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) def write(self, cr, uid, ids, vals, context=None): From eae045949d65fb4236e1d7b3fc3e806673711fe1 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 26 Apr 2016 14:45:16 +0200 Subject: [PATCH 19/68] [IMP] doc: simpler coding: utf-8 According to PEP-263, the -*- is just a variant "using formats recognized by popular editors". --- doc/reference/guidelines.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/reference/guidelines.rst b/doc/reference/guidelines.rst index e4cfe1255ec..5672aabf92c 100644 --- a/doc/reference/guidelines.rst +++ b/doc/reference/guidelines.rst @@ -271,7 +271,7 @@ Idioms - Always favor *Readability* over *conciseness* or using the language features or idioms. - Use list comprehension, dict comprehension, and basic manipulation using ``map``, ``filter``, ``sum``, ... They make the code easier to read. - The same applies for recordset methods : use ``filtered``, ``mapped``, ``sorted``, ... -- Each python file should have ``# -*- coding: utf-8 -*-`` as first line +- Each python file should have ``# coding: utf-8 `` as first line - Use the ``UserError`` defined in ``openerp.exceptions`` instead of overriding ``Warning``, or find a more appropriate exception in *exceptions.py* - Document your code (docstring on methods, simple comments for the tricky part of the code) - Use meaningful variable/class/method names From 842a8e6952992551cdc46e5ec23a48a3e4920b6e Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 26 Apr 2016 14:56:44 +0200 Subject: [PATCH 20/68] [IMP] doc: add guidelines warning To prevent huge chunk of modifications for styling reasons (e.g. mass PEP8 commits) --- doc/reference/guidelines.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/reference/guidelines.rst b/doc/reference/guidelines.rst index 5672aabf92c..54a00097705 100644 --- a/doc/reference/guidelines.rst +++ b/doc/reference/guidelines.rst @@ -11,6 +11,14 @@ aim to improve the quality of the code (better readability of source, ...) and Odoo Apps. Indeed, proper code ought ease maintenance, aid debugging, lower complexity and promote reliability. +.. warning:: + + These guidelines are written with new modules and new files in mind. When + modifying existing files, the original style of the file strictly supersedes + any other style guidelines. In other words, never modify existing files in + order to apply these guidelines, to avoid disrupting the revision history of + each line. For more details, see our `pull request guide `_. + Module structure ================ From 64e822c8259ae7d7410a4e91c6181e8959a5d041 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 25 Apr 2016 17:11:34 +0200 Subject: [PATCH 21/68] [FIX] account_asset: asset_create When creating assets from invoice lines, the system must check that assets have not already been created for the related invoice. If assets already exist then these assets have to be removed. Used case: - In the purchase journal, tick "allow canceling entries" - On a supplier invoice line, set an asset category - validate the invoice - cancel the invoice - set to draft - validate the invoice Before the fix: the asset is created twice. After the fix: the asset is created once. opw:674674 Note: This is a cherry-pick of commits 9d14230 and 58a5b5e --- addons/account_asset/account_asset_invoice.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py index e47d7cee668..c3e6add1042 100644 --- a/addons/account_asset/account_asset_invoice.py +++ b/addons/account_asset/account_asset_invoice.py @@ -17,8 +17,9 @@ class AccountInvoice(models.Model): result = super(AccountInvoice, self).action_number() for inv in self: if inv.number: - if self.env['account.asset.asset'].sudo().search([('code', '=', inv.number)]): - raise Warning(_('You already have assets with the reference %s.\nPlease delete these assets before creating new ones for this invoice.') % (inv.number,)) + asset_ids = self.env['account.asset.asset'].sudo().search([('invoice_id', '=', inv.id), ('company_id', '=', inv.company_id.id)]) + if asset_ids: + asset_ids.write({'active': False}) inv.invoice_line.asset_create() return result From 4606250d914bb18517d6f5713fcd33348553dadc Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 26 Apr 2016 15:51:00 +0200 Subject: [PATCH 22/68] [FIX] account: amount currency in journal items list view In 8.0, the amount currency field was displayed in the journal items list view when choosing, thanks to the `quick add` widget, a journal with a currency set. Otherwise, if the journal had no currency set, the column was not displayed. It was done thanks to the key "currency" passed in the context. From 9.0, the `quick add` is no longer used, and, due to that, the amount currency field was no longer displayed in the journal items list view at all, despite if the journal had a currency set or not. In technical words, `currency` was no longer passed in the context, making the invisibility property set with `invisible="not context.get('currency',False)"` useless. As this widget is no longer used, there is no other choice than either always display the column, either never. We choose to display it only if you have the multi-currency group (as this is the case in the journal item form view) We also take the opportunity to move the column next to the debit & credit column, this is more meaningful. opw-676059 --- addons/account/views/account_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 76ac76adf1b..c9c9fe7082d 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -1098,9 +1098,9 @@ + + - - From 0c2f7bdbc28e6261592efa880166ac93f85dfa48 Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Thu, 15 Oct 2015 10:52:34 +0200 Subject: [PATCH 23/68] [FIX] tools: export translated fields not included in _columns Non-stored new API computed fields are only defined in _fields but not in _columns, and they were never exported within translation files. Closes #9081 --- openerp/tools/translate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 794f0d3aed7..532d52e4f60 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -746,10 +746,10 @@ def trans_generate(lang, modules, cr): _logger.error("name error in %s: %s", xml_name, str(exc)) continue objmodel = registry.get(obj.model) - if (objmodel is None or field_name not in objmodel._columns + if (objmodel is None or field_name not in objmodel._fields or not objmodel._translate): continue - field_def = objmodel._columns[field_name] + field_def = objmodel._fields[field_name] name = "%s,%s" % (encode(obj.model), field_name) push_translation(module, 'field', name, 0, encode(field_def.string)) @@ -757,7 +757,7 @@ def trans_generate(lang, modules, cr): if field_def.help: push_translation(module, 'help', name, 0, encode(field_def.help)) - if field_def.translate: + if getattr(field_def, 'translate', None): ids = objmodel.search(cr, uid, []) obj_values = objmodel.read(cr, uid, ids, [field_name]) for obj_value in obj_values: From 7d25dd56180ec60d9167f0c975d95b261a08223d Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 27 Apr 2016 10:54:55 +0200 Subject: [PATCH 24/68] [IMP] payment_adyen: support autogenerated HMAC SHA-256 key From v4.1.0 of the documentation (2015-06-29), the HMAC SHA-1 key is deprecated. Indeed, it should be considered as a legacy option to guarantee compatibility with older skins. The HMAC SHA-256 key should be used instead, and moreover, it seems that any new skin created does not support SHA-1 at all, even if the option is available. The merchant signature code is inspired from the documentation example. Source: https://docs.adyen.com/developers/hpp-manual Fixes #9786 opw-676081 --- addons/payment_adyen/models/adyen.py | 111 ++++++++++++++++++++++----- addons/payment_adyen/views/adyen.xml | 4 + 2 files changed, 97 insertions(+), 18 deletions(-) diff --git a/addons/payment_adyen/models/adyen.py b/addons/payment_adyen/models/adyen.py index 4d28bbb4d03..d8d06042365 100644 --- a/addons/payment_adyen/models/adyen.py +++ b/addons/payment_adyen/models/adyen.py @@ -2,7 +2,9 @@ import base64 import json -from hashlib import sha1 +import binascii +from collections import OrderedDict +import hashlib import hmac import logging import urlparse @@ -39,8 +41,57 @@ class AcquirerAdyen(osv.Model): 'adyen_skin_hmac_key': fields.char('Skin HMAC Key', required_if_provider='adyen'), } + def _adyen_generate_merchant_sig_sha256(self, acquirer, inout, values): + """ Generate the shasign for incoming or outgoing communications., when using the SHA-256 + signature. + + :param browse acquirer: the payment.acquirer browse record. It should + have a shakey in shaky out + :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen + contacting openerp). In this last case only some + fields should be contained (see e-Commerce basic) + :param dict values: transaction values + :return string: shasign + """ + def escapeVal(val): + return val.replace('\\', '\\\\').replace(':', '\\:') + + def signParams(parms): + signing_string = ':'.join(map(escapeVal, parms.keys() + parms.values())) + hm = hmac.new(hmac_key, signing_string, hashlib.sha256) + return base64.b64encode(hm.digest()) + + assert inout in ('in', 'out') + assert acquirer.provider == 'adyen' + + if inout == 'in': + # All the fields sent to Adyen must be included in the signature. ALL the fucking + # fields, despite what is claimed in the documentation. For example, in + # https://docs.adyen.com/developers/hpp-manual, it is stated: "The resURL parameter does + # not need to be included in the signature." It's a trap, it must be included as well! + keys = [ + 'merchantReference', 'paymentAmount', 'currencyCode', 'shipBeforeDate', 'skinCode', + 'merchantAccount', 'sessionValidity', 'merchantReturnData', 'shopperEmail', + 'shopperReference', 'allowedMethods', 'blockedMethods', 'offset', + 'shopperStatement', 'recurringContract', 'billingAddressType', + 'deliveryAddressType', 'brandCode', 'countryCode', 'shopperLocale', 'orderData', + 'offerEmail', 'resURL', + ] + else: + keys = [ + 'authResult', 'merchantReference', 'merchantReturnData', 'paymentMethod', + 'pspReference', 'shopperLocale', 'skinCode', + ] + + hmac_key = binascii.a2b_hex(acquirer.adyen_skin_hmac_key.encode('ascii')) + raw_values = {k: values.get(k.encode('ascii'), '') for k in keys if k in values} + raw_values_ordered = OrderedDict(sorted(raw_values.items(), key=lambda t: t[0])) + + return signParams(raw_values_ordered) + def _adyen_generate_merchant_sig(self, acquirer, inout, values): - """ Generate the shasign for incoming or outgoing communications. + """ Generate the shasign for incoming or outgoing communications, when using the SHA-1 + signature (deprecated by Adyen). :param browse acquirer: the payment.acquirer browse record. It should have a shakey in shaky out @@ -66,7 +117,7 @@ class AcquirerAdyen(osv.Model): sign = ''.join('%s' % get_value(k) for k in keys).encode('ascii') key = acquirer.adyen_skin_hmac_key.encode('ascii') - return base64.b64encode(hmac.new(key, sign, sha1).digest()) + return base64.b64encode(hmac.new(key, sign, hashlib.sha1).digest()) def adyen_form_generate_values(self, cr, uid, id, values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') @@ -74,21 +125,42 @@ class AcquirerAdyen(osv.Model): # tmp import datetime from dateutil import relativedelta - tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) - values.update({ - 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), - 'currencyCode': values['currency'] and values['currency'].name or '', - 'shipBeforeDate': tmp_date, - 'skinCode': acquirer.adyen_skin_code, - 'merchantAccount': acquirer.adyen_merchant_account, - 'shopperLocale': values.get('partner_lang'), - 'sessionValidity': tmp_date, - 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), - 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url') else False, - 'merchantSig': self._adyen_generate_merchant_sig(acquirer, 'in', values), - }) + if acquirer.provider == 'adyen' and len(acquirer.adyen_skin_hmac_key) == 64: + tmp_date = datetime.datetime.today() + relativedelta.relativedelta(days=1) + + values.update({ + 'merchantReference': values['reference'], + 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'currencyCode': values['currency'] and values['currency'].name or '', + 'shipBeforeDate': tmp_date.strftime('%Y-%m-%d'), + 'skinCode': acquirer.adyen_skin_code, + 'merchantAccount': acquirer.adyen_merchant_account, + 'shopperLocale': values.get('partner_lang', ''), + 'sessionValidity': tmp_date.isoformat('T')[:19] + "Z", + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), + 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url', '') else False, + 'shopperEmail': values.get('partner_email', ''), + }) + values['merchantSig'] = self._adyen_generate_merchant_sig_sha256(acquirer, 'in', values) + + else: + tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) + + values.update({ + 'merchantReference': values['reference'], + 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'currencyCode': values['currency'] and values['currency'].name or '', + 'shipBeforeDate': tmp_date, + 'skinCode': acquirer.adyen_skin_code, + 'merchantAccount': acquirer.adyen_merchant_account, + 'shopperLocale': values.get('partner_lang'), + 'sessionValidity': tmp_date, + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), + 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url') else False, + 'merchantSig': self._adyen_generate_merchant_sig(acquirer, 'in', values), + }) + return values def adyen_get_form_action_url(self, cr, uid, id, context=None): @@ -123,7 +195,10 @@ class TxAdyen(osv.Model): tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) # verify shasign - shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, 'out', data) + if len(tx.acquirer_id.adyen_skin_hmac_key) == 64: + shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig_sha256(tx.acquirer_id, 'out', data) + else: + shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, 'out', data) if shasign_check != data.get('merchantSig'): error_msg = _('Adyen: invalid merchantSig, received %s, computed %s') % (data.get('merchantSig'), shasign_check) _logger.warning(error_msg) diff --git a/addons/payment_adyen/views/adyen.xml b/addons/payment_adyen/views/adyen.xml index 76856158030..ff92d21dce2 100644 --- a/addons/payment_adyen/views/adyen.xml +++ b/addons/payment_adyen/views/adyen.xml @@ -19,6 +19,10 @@ + +