Beispiel #1
0
    def authorize(self, amount, reference, token=None, opaque_data=None):
        """ Authorize (without capture) a payment for the given amount.

        :param float amount: The amount to pay
        :param str reference: The "invoiceNumber" in Authorize.net backend
        :param recordset token: The token of the payment method to charge, as a `payment.token`
                                record
        :param dict opaque_data: The payment details obfuscated by Authorize.Net
        :return: a dict containing the response code, transaction id and transaction type
        :rtype: dict
        """
        tx_data = self._prepare_tx_data(token=token, opaque_data=opaque_data)
        response = self._make_request(
            'createTransactionRequest', {
                'transactionRequest': {
                    'transactionType': 'authOnlyTransaction',
                    'amount': str(amount),
                    **tx_data,
                    'order': {
                        'invoiceNumber': reference[:20],
                        'description': reference[:255],
                    },
                    'customerIP': payment_utils.get_customer_ip_address(),
                }
            })
        return self._format_response(response, 'auth_only')
Beispiel #2
0
 def _prepare_authorization_transaction_request(self, transaction_type,
                                                tx_data, amount, reference):
     return {
         'transactionRequest': {
             'transactionType': transaction_type,
             'amount': str(amount),
             **tx_data,
             'order': {
                 'invoiceNumber': reference[:20],
                 'description': reference[:255],
             },
             'customerIP': payment_utils.get_customer_ip_address(),
         }
     }
Beispiel #3
0
    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)
Beispiel #4
0
    def _prepare_authorization_transaction_request(self, transaction_type,
                                                   tx_data, tx):
        # The billTo parameter is required for new ACH transactions (transactions without a payment.token),
        # but is not allowed for transactions with a payment.token.
        bill_to = {}
        if 'profile' not in tx_data:
            split_name = payment_utils.split_partner_name(tx.partner_name)
            partner_name = (tx.partner_name or
                            "")[:50]  # max length defined by the Authorize API
            bill_to = {
                'billTo': {
                    'firstName':
                    '' if tx.partner_id.is_company else split_name[0],
                    'lastName': split_name[1],  # lastName is always required
                    'company':
                    partner_name if tx.partner_id.is_company else '',
                    'address': tx.partner_address,
                    'city': tx.partner_city,
                    'state': tx.partner_state_id.name or '',
                    'zip': tx.partner_zip,
                    'country': tx.partner_country_id.name or '',
                }
            }

        # These keys have to be in the order defined in
        # https://apitest.authorize.net/xml/v1/schema/AnetApiSchema.xsd
        return {
            'transactionRequest': {
                'transactionType': transaction_type,
                'amount': str(tx.amount),
                **tx_data,
                'order': {
                    'invoiceNumber': tx.reference[:20],
                    'description': tx.reference[:255],
                },
                'customer': {
                    'email': tx.partner_email or '',
                },
                **bill_to,
                'customerIP': payment_utils.get_customer_ip_address(),
            }
        }
Beispiel #5
0
    def _send_payment_request(self):
        """ Override of payment to send a payment request to Flutterwave.

        Note: self.ensure_one()

        :return: None
        :raise UserError: If the transaction is not linked to a token.
        """
        super()._send_payment_request()
        if self.provider != 'flutterwave':
            return

        # Prepare the payment request to Flutterwave.
        if not self.token_id:
            raise UserError("Flutterwave: " +
                            _("The transaction is not linked to a token."))

        first_name, last_name = payment_utils.split_partner_name(
            self.partner_name)
        data = {
            'token': self.token_id.acquirer_ref,
            'email': self.token_id.flutterwave_customer_email,
            'amount': self.amount,
            'currency': self.currency_id.name,
            'country': self.company_id.country_id.code,
            'tx_ref': self.reference,
            'first_name': first_name,
            'last_name': last_name,
            'ip': payment_utils.get_customer_ip_address(),
        }

        # Make the payment request to Flutterwave.
        response_content = self.acquirer_id._flutterwave_make_request(
            'tokenized-charges', payload=data)

        # 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_notification_data('flutterwave', response_content['data'])
Beispiel #6
0
    def auth_and_capture(self,
                         amount,
                         reference,
                         token=None,
                         opaque_data=None):
        """Authorize and capture a payment for the given amount.

        Authorize and immediately capture a payment for the given payment.token
        record for the specified amount with reference as communication.

        :param str amount: transaction amount (up to 15 digits with decimal point)
        :param str reference: used as "invoiceNumber" in the Authorize.net backend
        :param record token: the payment.token record that must be charged
        :param str opaque_data: the transaction opaque_data obtained from Authorize.net

        :return: a dict containing the response code, transaction id and transaction type
        :rtype: dict
        """
        tx_data = self._prepare_tx_data(token=token, opaque_data=opaque_data)
        response = self._make_request(
            'createTransactionRequest', {
                'transactionRequest': {
                    'transactionType': 'authCaptureTransaction',
                    'amount': str(amount),
                    **tx_data,
                    'order': {
                        'invoiceNumber': reference[:20],
                        'description': reference[:255],
                    },
                    'customerIP': payment_utils.get_customer_ip_address(),
                }
            })

        result = self._format_response(response, 'auth_capture')
        errors = response.get('transactionResponse', {}).get('errors')
        if errors:
            result['x_response_reason_text'] = '\n'.join(
                [e.get('errorText') for e in errors])
        return result
Beispiel #7
0
    def adyen_payments(self,
                       acquirer_id,
                       reference,
                       converted_amount,
                       currency_id,
                       partner_id,
                       payment_method,
                       access_token,
                       browser_info=None):
        """ Make a payment request and process the feedback data.

        :param int acquirer_id: The acquirer handling the transaction, as a `payment.acquirer` id
        :param str reference: The reference of the transaction
        :param int converted_amount: The amount of the transaction in minor units of the currency
        :param int currency_id: The currency of the transaction, as a `res.currency` id
        :param int partner_id: The partner making the transaction, as a `res.partner` id
        :param dict payment_method: The details of the payment method used for the transaction
        :param str access_token: The access token used to verify the provided values
        :param dict browser_info: The browser info to pass to Adyen
        :return: The JSON-formatted content of the response
        :rtype: dict
        """
        # Check that the transaction details have not been altered. This allows preventing users
        # from validating transactions by paying less than agreed upon.
        if not payment_utils.check_access_token(access_token, reference,
                                                converted_amount, partner_id):
            raise ValidationError("Adyen: " +
                                  _("Received tampered payment request data."))

        # Make the payment request to Adyen
        acquirer_sudo = request.env['payment.acquirer'].sudo().browse(
            acquirer_id).exists()
        tx_sudo = request.env['payment.transaction'].sudo().search([
            ('reference', '=', reference)
        ])
        data = {
            'merchantAccount':
            acquirer_sudo.adyen_merchant_account,
            'amount': {
                'value': converted_amount,
                'currency': request.env['res.currency'].browse(
                    currency_id).name,  # ISO 4217
            },
            'reference':
            reference,
            'paymentMethod':
            payment_method,
            'shopperReference':
            acquirer_sudo._adyen_compute_shopper_reference(partner_id),
            'recurringProcessingModel':
            'CardOnFile',  # Most susceptible to trigger a 3DS check
            'shopperIP':
            payment_utils.get_customer_ip_address(),
            'shopperInteraction':
            'Ecommerce',
            'storePaymentMethod':
            tx_sudo.tokenize,  # True by default on Adyen side
            'additionalData': {
                'allow3DS2': True
            },
            'channel':
            'web',  # Required to support 3DS
            'origin':
            acquirer_sudo.get_base_url(),  # Required to support 3DS
            'browserInfo':
            browser_info,  # Required to support 3DS
            'returnUrl':
            urls.url_join(
                acquirer_sudo.get_base_url(),
                # Include the reference in the return url to be able to match it after redirection.
                # The key 'merchantReference' is chosen on purpose to be the same as that returned
                # by the /payments endpoint of Adyen.
                f'/payment/adyen/return?merchantReference={reference}'),
        }
        response_content = acquirer_sudo._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",
            reference, pprint.pformat(response_content))
        request.env['payment.transaction'].sudo()._handle_feedback_data(
            'adyen',
            dict(response_content,
                 merchantReference=reference),  # Match the transaction
        )
        return response_content