Files
odoo_source/addons/payment_odoo/controllers/main.py
T
Kevin BaptisteandAntoine Prieels 208a82f344 [IMP] adyen_platforms,payment_odoo: add notification support
- Improved onboarding / KYC flow
    - Display KYC stage for each "document" (identity, bank account,
    shareholder, etc.)
    - Only update to the API what's been updated by the user to prevent
    undergoing another full round of data verification

- Show new pricing

- Support refund of adyen.transaction

- Simplify payouts (let Adyen automatically handle them)
    - They are now automatically handled by Adyen and not manually
    triggered by a cron

- "Balance" dashboard
    - Show the balance per currency
    - List of payouts and their status

- Handle account/transaction notifications
    - Show split of fees
    - Details on payment method (card country, card type, etc.) used
    - Display details from the linked payment.transaction

- Verify proxy signature for notifications
    - Notifications are now signed and authenticity verified

TaskID: 2129218
Closes odoo/odoo#68952

Co-authored-by: Antoine Prieels <anp@odoo.com>
2021-06-02 14:12:40 +00:00

94 lines
3.7 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging
import pprint
from odoo import http
from odoo.http import request
from odoo.addons.payment import utils as payment_utils
from odoo.addons.payment_odoo.const import CURRENCY_DECIMALS
_logger = logging.getLogger(__name__)
class OdooController(http.Controller):
_notification_url = '/payment/odoo/notification'
@http.route(_notification_url, type='json', auth='public')
def odoo_notification(self):
""" Process the data sent by Adyen to the webhook based on the event code.
See https://docs.adyen.com/development-resources/webhooks/understand-notifications for the
exhaustive list of event codes.
:return: None
"""
# Payload data represent a single notification's data. Because two notifications of a same
# batch can be related to different sub-merchants, the proxy splits the batches and send
# individual notifications one by one to this endpoint.
notification_data = json.loads(request.httprequest.data)
# Check the source and integrity of the notification
received_signature = notification_data.get('additionalData', {}).get(
'metadata.merchant_signature'
)
tx_sudo = request.env['payment.transaction'].sudo()._get_tx_from_feedback_data(
'odoo', notification_data
)
# Ignore signature for REFUND, the signature will be the one of the original transaction
event_code = notification_data['eventCode']
if event_code != 'REFUND' and not self._verify_notification_signature(
received_signature, tx_sudo
):
return
_logger.info("notification received:\n%s", pprint.pformat(notification_data))
if notification_data['success'] != 'true' and event_code != 'REFUND':
return # Don't handle failed events
request.env['adyen.transaction'].sudo()._handle_payment_notification(
notification_data, tx_sudo
)
# Reshape the notification data for parsing
if event_code == 'AUTHORISATION':
notification_data['resultCode'] = 'Authorised'
elif event_code == 'CANCELLATION':
notification_data['resultCode'] = 'Cancelled'
elif event_code in ['NOTIFICATION_OF_CHARGEBACK', 'CHARGEBACK']:
notification_data['resultCode'] = 'Chargeback'
elif event_code == 'REFUND':
notification_data['resultCode'] = 'Refund'
else:
return # Don't handle unsupported event codes
# Handle the notification data as a regular feedback
request.env['payment.transaction'].sudo()._handle_feedback_data('odoo', notification_data)
def _verify_notification_signature(self, received_signature, tx):
""" Check that the signature computed from the transaction values matches the received one.
:param str received_signature: The signature sent with the notification
:param recordset tx: The transaction of the notification, as a `payment.transaction` record
:return: Whether the signatures match
:rtype: str
"""
if not received_signature:
_logger.warning("ignored notification with missing signature")
return False
converted_amount = payment_utils.to_minor_currency_units(
tx.amount, tx.currency_id, CURRENCY_DECIMALS.get(tx.currency_id.name)
)
if not payment_utils.check_access_token(
received_signature, converted_amount, tx.currency_id.name, tx.reference
):
_logger.warning("ignored notification with invalid signature")
return False
return True