[FIX] payment: avoid a mismatch between partner's and acquirer's company

In a multi-company environment, a partner of company A should not be able
to make payments for company B. With this commit, if we detect a
mismatch between the companies, a UserError is raised.

Task - 2627751

closes odoo/odoo#91189

X-original-commit: 6064cf2e98f16b42f516dcd1b0793a62436bab33
Related: odoo/enterprise#27245
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
Signed-off-by: Horacio Tellez Perez (hote) <hote@odoo.com>
This commit is contained in:
Horacio Tellez
2022-05-12 13:43:36 +02:00
parent 959f3ad8b0
commit 89bb842246
4 changed files with 44 additions and 6 deletions
+10 -6
View File
@@ -4,6 +4,7 @@
from odoo.http import request
from odoo.addons.account.controllers import portal
from odoo.addons.payment.controllers.portal import PaymentPortal
from odoo.addons.portal.controllers.portal import _build_url_w_params
@@ -15,14 +16,17 @@ class PortalAccount(portal.PortalAccount):
# We set partner_id to the partner id of the current user if logged in, otherwise we set it
# to the invoice partner id. We do this to ensure that payment tokens are assigned to the
# correct partner and to avoid linking tokens to the public user.
partner_id = request.env.user.partner_id.id if logged_in else invoice.partner_id.id
partner = request.env.user.partner_id if logged_in else invoice.partner_id
# Make sure that the partner's company matches the invoice's company.
invoice_company = invoice.company_id or request.env.company
PaymentPortal.ensure_matching_companies(partner, invoice_company)
acquirers_sudo = request.env['payment.acquirer'].sudo()._get_compatible_acquirers(
invoice.company_id.id or request.env.company.id,
partner_id,
currency_id=invoice.currency_id.id,
invoice_company.id, partner.id, currency_id=invoice.currency_id.id
) # In sudo mode to read the fields of acquirers and partner (if not logged in)
tokens = request.env['payment.token'].search(
[('acquirer_id', 'in', acquirers_sudo.ids), ('partner_id', '=', partner_id)]
[('acquirer_id', 'in', acquirers_sudo.ids), ('partner_id', '=', partner.id)]
) # Tokens are cleared at the end if the user is not logged in
fees_by_acquirer = {
acq_sudo: acq_sudo._compute_fees(
@@ -36,7 +40,7 @@ class PortalAccount(portal.PortalAccount):
'show_tokenize_input': logged_in, # Prevent public partner from saving payment methods
'amount': invoice.amount_residual,
'currency': invoice.currency_id,
'partner_id': partner_id,
'partner_id': partner.id,
'access_token': access_token,
'transaction_route': f'/invoice/transaction/{invoice.id}/',
'landing_route': _build_url_w_params(invoice.access_url, {'access_token': access_token})
+22
View File
@@ -103,6 +103,9 @@ class PaymentPortal(portal.CustomerPortal):
company = request.env['res.company'].sudo().browse(company_id)
currency_id = currency_id or company.currency_id.id
# Make sure that the company passed as parameter matches the partner's company.
PaymentPortal.ensure_matching_companies(partner_sudo, company)
# Make sure that the currency exists and is active
currency = request.env['res.currency'].browse(currency_id).exists()
if not currency or not currency.active:
@@ -429,3 +432,22 @@ class PaymentPortal(portal.CustomerPortal):
return float(str_value)
except (TypeError, ValueError, OverflowError):
return None
@staticmethod
def ensure_matching_companies(partner, document_company):
""" Check that the partner's company is the same as the document's company.
If the partner company is not set, the check passes. If the companies don't match, a
`UserError` is raised.
:param recordset partner: The partner on behalf on which the payment is made, as a
`res.partner` record.
:param recordset document_company: The company of the document being paid, as a
`res.company` record.
:return: None
:raise UserError: If the companies don't match.
"""
if partner.company_id and partner.company_id != document_company:
raise UserError(
_("Please switch to company '%s' to make this payment.", document_company.name)
)
+6
View File
@@ -1399,6 +1399,12 @@ msgstr ""
msgid "Please set an amount smaller than %s."
msgstr ""
#. module: payment
#: code:addons/payment/controllers/portal.py:0
#, python-format
msgid "Please switch to company '%s' to make this payment."
msgstr ""
#. module: payment
#: model_terms:payment.acquirer,pending_msg:payment.payment_acquirer_transfer
msgid "Please use the following transfer details"
+6
View File
@@ -152,6 +152,12 @@ class CustomerPortal(portal.CustomerPortal):
# Payment values
if order_sudo.has_to_be_paid():
logged_in = not request.env.user._is_public()
# Make sure that the partner's company matches the sales order's company.
payment_portal.PaymentPortal.ensure_matching_companies(
order_sudo.partner_id, order_sudo.company_id
)
acquirers_sudo = request.env['payment.acquirer'].sudo()._get_compatible_acquirers(
order_sudo.company_id.id,
order_sudo.partner_id.id,