From 8b027b69cea7f0248e35385317d3f64cd02c5cba Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Tue, 4 Oct 2022 13:10:50 +0000 Subject: [PATCH] [FIX] payment_adyen: add missing fields to api call It's needed to use "Automatic Risk assessment" feature in Adyen. Technical docs: https://docs.adyen.com/risk-management/configure-manual-risk/required-risk-field-reference opw-3004646 X-original-commit: a8a166086b41692af49e0a9d4c44c0afdc0e05d4 Part-of: odoo/odoo#105664 --- addons/payment_adyen/controllers/main.py | 5 ++ .../models/payment_transaction.py | 5 ++ addons/payment_adyen/utils.py | 57 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 addons/payment_adyen/utils.py diff --git a/addons/payment_adyen/controllers/main.py b/addons/payment_adyen/controllers/main.py index af127715262..019bb78f403 100644 --- a/addons/payment_adyen/controllers/main.py +++ b/addons/payment_adyen/controllers/main.py @@ -15,6 +15,7 @@ from odoo.exceptions import ValidationError from odoo.http import request from odoo.addons.payment import utils as payment_utils +from odoo.addons.payment_adyen import utils as adyen_utils from odoo.addons.payment_adyen.const import CURRENCY_DECIMALS _logger = logging.getLogger(__name__) @@ -120,6 +121,9 @@ class AdyenController(http.Controller): 'recurringProcessingModel': 'CardOnFile', # Most susceptible to trigger a 3DS check 'shopperIP': payment_utils.get_customer_ip_address(), 'shopperInteraction': 'Ecommerce', + 'shopperEmail': tx_sudo.partner_email, + 'shopperName': adyen_utils.format_partner_name(tx_sudo.partner_name), + 'telephoneNumber': tx_sudo.partner_phone, 'storePaymentMethod': tx_sudo.tokenize, # True by default on Adyen side 'additionalData': { 'allow3DS2': True @@ -134,6 +138,7 @@ class AdyenController(http.Controller): # by the /payments endpoint of Adyen. f'/payment/adyen/return?merchantReference={reference}' ), + **adyen_utils.include_partner_addresses(tx_sudo), } # Force the capture delay on Adyen side if the provider is not configured for capturing diff --git a/addons/payment_adyen/models/payment_transaction.py b/addons/payment_adyen/models/payment_transaction.py index cf3d7989b54..00effca73f5 100644 --- a/addons/payment_adyen/models/payment_transaction.py +++ b/addons/payment_adyen/models/payment_transaction.py @@ -7,6 +7,7 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError from odoo.addons.payment import utils as payment_utils +from odoo.addons.payment_adyen import utils as adyen_utils from odoo.addons.payment_adyen.const import CURRENCY_DECIMALS, RESULT_CODES_MAPPING _logger = logging.getLogger(__name__) @@ -75,6 +76,10 @@ class PaymentTransaction(models.Model): 'recurringProcessingModel': 'Subscription', 'shopperIP': payment_utils.get_customer_ip_address(), 'shopperInteraction': 'ContAuth', + 'shopperEmail': self.partner_email, + 'shopperName': adyen_utils.format_partner_name(self.partner_name), + 'telephoneNumber': self.partner_phone, + **adyen_utils.include_partner_addresses(self), } # Force the capture delay on Adyen side if the provider is not configured for capturing diff --git a/addons/payment_adyen/utils.py b/addons/payment_adyen/utils.py new file mode 100644 index 00000000000..eaea4faf5cd --- /dev/null +++ b/addons/payment_adyen/utils.py @@ -0,0 +1,57 @@ +from odoo.addons.payment import utils as payment_utils + + +def format_partner_name(partner_name): + """ Format the partner name to comply with the payload structure of the API request. + + :param str partner_name: The name of the partner making the payment. + :return: The formatted partner name. + :rtype: dict + """ + first_name, last_name = payment_utils.split_partner_name(partner_name) + return { + 'firstName': first_name, + 'lastName': last_name, + } + + +def include_partner_addresses(tx_sudo): + """ Include the billing and delivery addresses of the related sales order to the payload of the + API request. + + If no related sales order exists, the addresses are not included. + + Note: `self.ensure_one()` + + :param payment.transaction tx_sudo: The sudoed transaction of the payment. + :return: The subset of the API payload that includes the billing and delivery addresses. + :rtype: dict + """ + tx_sudo.ensure_one() + + if 'sale_order_ids' in tx_sudo._fields: # The module `sale` is installed. + order = tx_sudo.sale_order_ids[:1] + if order: + return { + 'billingAddress': format_partner_address(order.partner_invoice_id), + 'deliveryAddress': format_partner_address(order.partner_shipping_id), + } + return {} + + +def format_partner_address(partner): + """ Format the partner address to comply with the payload structure of the API request. + + :param res.partner partner: The partner making the payment. + :return: The formatted partner address. + :rtype: dict + """ + street_data = partner._get_street_split() + return { + 'city': partner.city, + 'country': partner.country_id.code or 'ZZ', # 'ZZ' if the country is not known. + 'stateOrProvince': partner.state_id.code, + 'postalCode': partner.zip, + 'street': street_data['street_name'], + 'houseNumberOrName': street_data['street_number'], + }