[FIX] payment,sale: access error in payment link
When a user was opening the payment_link_wizard and tried to select a preferred payment acquirer, he was getting an AccessError telling that he was not allowed to access 'payment.acquirer' records. Fix PR #69334 (task-2504225) task-2666881 closes odoo/odoo#80005 X-original-commit: 2ff580c073ac105219582dbf2108a1437645c9b5 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml import etree
|
||||
from werkzeug import urls
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
@@ -31,6 +31,41 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
})
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def fields_view_get(self, *args, **kwargs):
|
||||
""" Overrides orm fields_view_get
|
||||
|
||||
Using a Many2One field, when a user opens this wizard and tries to select a preferred
|
||||
payment acquirer, he will get an AccessError telling that he is not allowed to access
|
||||
'payment.acquirer' records. This error is thrown because the Many2One field is filled
|
||||
by the name_get() function and users don't have clearance to read 'payment.acquirer' records.
|
||||
|
||||
This override allows replacing the Many2One with a selection field, that is prefilled in the
|
||||
backend with the name of available acquirers. Therefore, Users will be able to select their
|
||||
preferred acquirer.
|
||||
|
||||
:return: composition of the requested view (including inherited views and extensions)
|
||||
:rtype: dict
|
||||
"""
|
||||
res = super().fields_view_get(*args, **kwargs)
|
||||
if res['type'] == 'form':
|
||||
doc = etree.XML(res['arch'])
|
||||
|
||||
# Replace acquirer_id with payment_acquirer_selection in the view
|
||||
acq = doc.xpath("//field[@name='acquirer_id']")[0]
|
||||
acq.attrib['name'] = 'payment_acquirer_selection'
|
||||
acq.attrib['widget'] = 'selection'
|
||||
acq.attrib['string'] = 'Force Payment Acquirer'
|
||||
del acq.attrib['options']
|
||||
del acq.attrib['placeholder']
|
||||
|
||||
# Replace acquirer_id with payment_acquirer_selection in the fields list
|
||||
xarch, xfields = self.env['ir.ui.view'].postprocess_and_fields(doc, model=self._name)
|
||||
|
||||
res['arch'] = xarch
|
||||
res['fields'] = xfields
|
||||
return res
|
||||
|
||||
res_model = fields.Char('Related Document Model', required=True)
|
||||
res_id = fields.Integer('Related Document ID', required=True)
|
||||
amount = fields.Monetary(currency_field='currency_id', required=True)
|
||||
@@ -58,6 +93,14 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
string="Has Multiple Acquirers",
|
||||
compute='_compute_has_multiple_acquirers',
|
||||
)
|
||||
payment_acquirer_selection = fields.Selection(
|
||||
string="Payment acquirer selected",
|
||||
selection='_selection_payment_acquirer_selection',
|
||||
default='all',
|
||||
compute='_compute_payment_acquirer_selection',
|
||||
inverse='_inverse_payment_acquirer_selection',
|
||||
required=True,
|
||||
)
|
||||
|
||||
@api.onchange('amount', 'description')
|
||||
def _onchange_amount(self):
|
||||
@@ -66,7 +109,7 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
if self.amount <= 0:
|
||||
raise ValidationError(_("The value of the payment amount must be positive."))
|
||||
|
||||
@api.depends('amount', 'description', 'partner_id', 'currency_id', 'acquirer_id')
|
||||
@api.depends('amount', 'description', 'partner_id', 'currency_id', 'payment_acquirer_selection')
|
||||
def _compute_values(self):
|
||||
for payment_link in self:
|
||||
payment_link.access_token = payment_utils.generate_access_token(
|
||||
@@ -84,12 +127,57 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
@api.depends('company_id', 'partner_id', 'currency_id')
|
||||
def _compute_available_acquirer_ids(self):
|
||||
for link in self:
|
||||
link.available_acquirer_ids = link.env['payment.acquirer']._get_compatible_acquirers(
|
||||
link.available_acquirer_ids = link._get_payment_acquirer_available(
|
||||
res_model=link.res_model,
|
||||
res_id=link.res_id,
|
||||
company_id=link.company_id.id,
|
||||
partner_id=link.partner_id.id,
|
||||
currency_id=link.currency_id.id
|
||||
currency_id=link.currency_id.id,
|
||||
)
|
||||
|
||||
@api.depends('acquirer_id')
|
||||
def _compute_payment_acquirer_selection(self):
|
||||
for link in self:
|
||||
link.payment_acquirer_selection = link.acquirer_id.id if link.acquirer_id else 'all'
|
||||
|
||||
def _inverse_payment_acquirer_selection(self):
|
||||
for link in self:
|
||||
link.acquirer_id = link.payment_acquirer_selection if link.payment_acquirer_selection != 'all' else False
|
||||
|
||||
def _selection_payment_acquirer_selection(self):
|
||||
""" Specify available acquirers in the selection field.
|
||||
:return: The selection list of available acquirers.
|
||||
:rtype: list[tuple]
|
||||
"""
|
||||
defaults = self.default_get(['res_model', 'res_id'])
|
||||
selection = [('all', "All")]
|
||||
res_model, res_id = defaults['res_model'], defaults['res_id']
|
||||
if res_id and res_model in ['account.move', "sale.order"]:
|
||||
# At module install, the selection method is called
|
||||
# but the document context isn't specified.
|
||||
related_document = self.env[res_model].browse(res_id)
|
||||
company_id = related_document.company_id
|
||||
partner_id = related_document.partner_id
|
||||
currency_id = related_document.currency_id
|
||||
selection.extend(
|
||||
self._get_payment_acquirer_available(
|
||||
res_model=res_model,
|
||||
res_id=res_id,
|
||||
company_id=company_id.id,
|
||||
partner_id=partner_id.id,
|
||||
currency_id=currency_id.id,
|
||||
).name_get()
|
||||
)
|
||||
return selection
|
||||
|
||||
def _get_payment_acquirer_available(self, **kwargs):
|
||||
""" Select and return the acquirers matching the criteria.
|
||||
|
||||
:return: The compatible acquirers
|
||||
:rtype: recordset of `payment.acquirer`
|
||||
"""
|
||||
return self.env['payment.acquirer'].sudo()._get_compatible_acquirers(**kwargs)
|
||||
|
||||
@api.depends('available_acquirer_ids')
|
||||
def _compute_has_multiple_acquirers(self):
|
||||
for link in self:
|
||||
@@ -106,5 +194,5 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
f'&partner_id={payment_link.partner_id.id}' \
|
||||
f'&company_id={payment_link.company_id.id}' \
|
||||
f'&invoice_id={payment_link.res_id}' \
|
||||
f'{"&acquirer_id=" + str(payment_link.acquirer_id.id) if payment_link.acquirer_id else "" }' \
|
||||
f'{"&acquirer_id=" + str(payment_link.payment_acquirer_selection) if payment_link.payment_acquirer_selection != "all" else "" }' \
|
||||
f'&access_token={payment_link.access_token}'
|
||||
|
||||
@@ -24,16 +24,17 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
})
|
||||
return res
|
||||
|
||||
@api.depends('company_id', 'partner_id', 'currency_id')
|
||||
def _compute_available_acquirer_ids(self):
|
||||
sale_links = self.filtered(lambda link: link.res_model == 'sale.order')
|
||||
super(PaymentLinkWizard, self-sale_links)._compute_available_acquirer_ids()
|
||||
for link in sale_links:
|
||||
link.available_acquirer_ids = link.env['payment.acquirer']._get_compatible_acquirers(
|
||||
company_id=link.company_id.id,
|
||||
partner_id=link.partner_id.id,
|
||||
currency_id=link.currency_id.id,
|
||||
sale_order_id=link.res_id)
|
||||
def _get_payment_acquirer_available(self, res_model, res_id, **kwargs):
|
||||
""" Select and return the acquirers matching the criteria.
|
||||
|
||||
:param str res_model: active model
|
||||
:param int res_id: id of 'active_model' record
|
||||
:return: The compatible acquirers
|
||||
:rtype: recordset of `payment.acquirer`
|
||||
"""
|
||||
if res_model == 'sale.order':
|
||||
kwargs['sale_order_id'] = res_id
|
||||
return super()._get_payment_acquirer_available(**kwargs)
|
||||
|
||||
def _generate_link(self):
|
||||
""" Override of payment to add the sale_order_id in the link. """
|
||||
@@ -46,7 +47,7 @@ class PaymentLinkWizard(models.TransientModel):
|
||||
f'?reference={urls.url_quote(payment_link.description)}' \
|
||||
f'&amount={payment_link.amount}' \
|
||||
f'&sale_order_id={payment_link.res_id}' \
|
||||
f'{"&acquirer_id=" + str(payment_link.acquirer_id.id) if payment_link.acquirer_id else "" }' \
|
||||
f'{"&acquirer_id=" + str(payment_link.payment_acquirer_selection) if payment_link.payment_acquirer_selection != "all" else "" }' \
|
||||
f'&access_token={payment_link.access_token}'
|
||||
# Order-related fields are retrieved in the controller
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user