Commit ceb8b78 introduced a mechanism to throw an error if some address fields were empty. The mechanism was introduced to prevent us from sending False as an address detail to Adyen when it was not set since it might negatively affect the fraud check score. It however caused some payments not to go through because it relied on Odoo's utils to extract the house number from the address, which would fail in some circumstances (e.g., when the number is placed before the street name). In some other cases, empty address details that were previously accepted by Adyen caused the error to be thrown. With this commit, we now pass Unknown instead of False or empty string for the address details that are not set and that are not required by Adyen in practice, unlike what is stated in AVS documentation. This delegates the responsibility to block the payment to Adyen as the address check and the related error are removed from Odoo. closes odoo/odoo#149365 X-original-commit: 771b7ebd55646d8c96938e562802b47cb92d18fb Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com> Signed-off-by: anko-odoo <anko@odoo.com>
66 lines
2.5 KiB
Python
66 lines
2.5 KiB
Python
from odoo import _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
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()
|
|
# Unlike what is stated in https://docs.adyen.com/risk-management/avs-checks/, not all fields
|
|
# are required at all time. Thus, we fall back to 'Unknown' when a field is not set to avoid
|
|
# blocking the payment (empty string are not accepted) or passing `False` (which may not pass
|
|
# the fraud check).
|
|
return {
|
|
'city': partner.city or 'Unknown',
|
|
'country': partner.country_id.code or 'ZZ', # 'ZZ' if the country is not known.
|
|
'stateOrProvince': partner.state_id.code or 'Unknown', # The state is not always required.
|
|
'postalCode': partner.zip or '',
|
|
# Fill in the address fields if the format is supported, or fallback to the raw address.
|
|
'street': street_data.get('street_name', partner.street) or 'Unknown',
|
|
'houseNumberOrName': street_data.get('street_number') or '',
|
|
}
|