def _send_refund_request(self, amount_to_refund=None, create_refund_transaction=True): """ Override of payment to send a refund request to Adyen. Note: self.ensure_one() :param float amount_to_refund: The amount to refund :param bool create_refund_transaction: Whether a refund transaction should be created or not :return: The refund transaction if any :rtype: recordset of `payment.transaction` """ if self.provider != 'adyen': return super()._send_refund_request( amount_to_refund=amount_to_refund, create_refund_transaction=create_refund_transaction ) refund_tx = super()._send_refund_request( amount_to_refund=amount_to_refund, create_refund_transaction=True ) # Make the refund request to Adyen converted_amount = payment_utils.to_minor_currency_units( -refund_tx.amount, # The amount is negative for refund transactions refund_tx.currency_id, arbitrary_decimal_number=CURRENCY_DECIMALS.get(refund_tx.currency_id.name) ) data = { 'merchantAccount': self.acquirer_id.adyen_merchant_account, 'amount': { 'value': converted_amount, 'currency': refund_tx.currency_id.name, }, 'reference': refund_tx.reference, } response_content = refund_tx.acquirer_id._adyen_make_request( url_field_name='adyen_checkout_api_url', endpoint='/payments/{}/refunds', endpoint_param=self.acquirer_reference, payload=data, method='POST' ) _logger.info( "refund request response for transaction with reference %s:\n%s", self.reference, pprint.pformat(response_content) ) # Handle the refund request response psp_reference = response_content.get('pspReference') status = response_content.get('status') if psp_reference and status == 'received': # The PSP reference associated with this /refunds request is different from the psp # reference associated with the original payment request. refund_tx.acquirer_reference = psp_reference return refund_tx
def _send_payment_request(self): """ Override of payment to send a payment request to Adyen. Note: self.ensure_one() :return: None :raise: UserError if the transaction is not linked to a token """ super()._send_payment_request() if self.provider != 'adyen': return # Make the payment request to Adyen if not self.token_id: raise UserError("Adyen: " + _("The transaction is not linked to a token.")) converted_amount = payment_utils.to_minor_currency_units( self.amount, self.currency_id, CURRENCY_DECIMALS.get(self.currency_id.name) ) data = { 'merchantAccount': self.acquirer_id.adyen_merchant_account, 'amount': { 'value': converted_amount, 'currency': self.currency_id.name, }, 'reference': self.reference, 'paymentMethod': { 'recurringDetailReference': self.token_id.acquirer_ref, }, 'shopperReference': self.token_id.adyen_shopper_reference, 'recurringProcessingModel': 'Subscription', 'shopperIP': payment_utils.get_customer_ip_address(), 'shopperInteraction': 'ContAuth', } response_content = self.acquirer_id._adyen_make_request( url_field_name='adyen_checkout_api_url', endpoint='/payments', payload=data, method='POST' ) # Handle the payment request response _logger.info( "payment request response for transaction with reference %s:\n%s", self.reference, pprint.pformat(response_content) ) self._handle_feedback_data('adyen', response_content)
def adyen_payment_methods(self, acquirer_id, amount=None, currency_id=None, partner_id=None): """ Query the available payment methods based on the transaction context. :param int acquirer_id: The acquirer handling the transaction, as a `payment.acquirer` id :param float amount: The transaction amount :param int currency_id: The transaction currency, as a `res.currency` id :param int partner_id: The partner making the transaction, as a `res.partner` id :return: The JSON-formatted content of the response :rtype: dict """ acquirer_sudo = request.env['payment.acquirer'].sudo().browse( acquirer_id) currency = request.env['res.currency'].browse(currency_id) currency_code = currency_id and currency.name converted_amount = amount and currency_code and payment_utils.to_minor_currency_units( amount, currency, CURRENCY_DECIMALS.get(currency_code)) partner_sudo = partner_id and request.env['res.partner'].sudo().browse( partner_id).exists() # The lang is taken from the context rather than from the partner because it is not required # to be logged in to make a payment, and because the lang is not always set on the partner. # Adyen only supports a limited set of languages but, instead of looking for the closest # match in https://docs.adyen.com/checkout/components-web/localization-components, we simply # provide the lang string as is (after adapting the format) and let Adyen find the best fit. lang_code = (request.context.get('lang') or 'en-US').replace('_', '-') shopper_reference = partner_sudo and f'ODOO_PARTNER_{partner_sudo.id}' data = { 'merchantAccount': acquirer_sudo.adyen_merchant_account, 'amount': converted_amount, 'countryCode': partner_sudo.country_id.code or None, # ISO 3166-1 alpha-2 (e.g.: 'BE') 'shopperLocale': lang_code, # IETF language tag (e.g.: 'fr-BE') 'shopperReference': shopper_reference, 'channel': 'Web', } response_content = acquirer_sudo._adyen_make_request( url_field_name='adyen_checkout_api_url', endpoint='/paymentMethods', payload=data, method='POST') _logger.info("paymentMethods request response:\n%s", pprint.pformat(response_content)) return response_content
def _get_specific_processing_values(self, processing_values): """ Override of payment to return Adyen-specific processing values. Note: self.ensure_one() from `_get_processing_values` :param dict processing_values: The generic processing values of the transaction :return: The dict of acquirer-specific processing values :rtype: dict """ res = super()._get_specific_processing_values(processing_values) if self.provider != 'adyen': return res converted_amount = payment_utils.to_minor_currency_units( self.amount, self.currency_id, CURRENCY_DECIMALS.get(self.currency_id.name)) return { 'converted_amount': converted_amount, 'access_token': payment_utils.generate_access_token( processing_values['reference'], converted_amount, processing_values['partner_id']) }