def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        try:
            req = self._post('Payment/v1/PaymentPage/Initialize',
                             json=self._get_payment_page_init_body(payment))
            req.raise_for_status()
        except HTTPError:
            logger.exception('Saferpay error: %s' % req.text)
            try:
                payment.info_data = req.json()
            except:
                payment.info_data = {'error': True, 'detail': req.text}
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action(
                'pretix.event.order.payment.failed', {
                    'local_id': payment.local_id,
                    'provider': payment.provider,
                    'data': payment.info_data
                })
            raise PaymentException(
                _('We had trouble communicating with Saferpay. Please try again and get in touch '
                  'with us if this problem persists.'))

        data = req.json()
        payment.info = json.dumps(data)
        payment.state = OrderPayment.PAYMENT_STATE_CREATED
        payment.save()
        request.session['payment_saferpay_order_secret'] = payment.order.secret
        return self.redirect(request, data.get('RedirectUrl'))
예제 #2
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        try:
            req = requests.post('https://api.mollie.com/v2/payments',
                                json=self._get_payment_body(payment),
                                headers=self.request_headers)
            req.raise_for_status()
        except HTTPError:
            logger.exception('Mollie error: %s' % req.text)
            try:
                payment.info_data = req.json()
            except:
                payment.info_data = {'error': True, 'detail': req.text}
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action(
                'pretix.event.order.payment.failed', {
                    'local_id': payment.local_id,
                    'provider': payment.provider,
                    'data': payment.info_data
                })
            raise PaymentException(
                _('We had trouble communicating with Mollie. Please try again and get in touch '
                  'with us if this problem persists.'))

        data = req.json()
        payment.info = json.dumps(data)
        payment.state = OrderPayment.PAYMENT_STATE_CREATED
        payment.save()
        request.session['payment_mollie_order_secret'] = payment.order.secret
        return self.redirect(request,
                             data.get('_links').get('checkout').get('href'))
예제 #3
0
def orderpayment(order, date, remind_after, reminded=None, old_format=True):
    op_date = date
    op = OrderPayment(order=order,
                      amount=11,
                      provider='sepadebit',
                      state=OrderPayment.PAYMENT_STATE_CONFIRMED)
    info_data = {
        'testdata': 'is not deleted',
        'account': 'Testaccount',
        'iban': 'DE02120300000000202051',
        'bic': 'BYLADEM1001',
        'reference': 'TESTREF-123'
    }

    if old_format:
        info_data['date'] = op_date.strftime("%Y-%m-%d")
        info_data['remind_after'] = remind_after.strftime("%Y-%m-%d-%H-%M-%S")
        info_data['reminded'] = reminded
        op.info_data = info_data
        op.save()
    else:
        op.info_data = info_data
        op.save()
        due_date = SepaDueDate(date=op_date,
                               reminded=reminded,
                               remind_after=remind_after)
        due_date.payment = op
        due_date.save()
    return op
예제 #4
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        try:
            # Get the correct endpoint to consume
            x_endpoint = self.get_settings_key('x_endpoint')
            if x_endpoint == 'live':
                url = 'https://payments.qpaypro.com/checkout/api_v1'
            else:
                url = 'https://sandbox.qpaypro.com/payment/api_v1'

            # Get the message body
            payment_body = self._get_payment_body(request, payment)

            # # To save the information befor send
            # # TO DO: to delete this action because of security issues
            # payment.order.log_action('pretix.event.order.payment.started', {
            #     'local_id': payment.local_id,
            #     'provider': payment.provider,
            #     'data': payment_body
            # })

            # Perform the call to the endpoint
            req = requests.post(
                url,
                json=payment_body,
            )
            req.raise_for_status()

            # Load the response to be read
            data = req.json()

            # The result is evaluated to determine the next step
            if not (data['result'] == 1 and data['responseCode'] == 100):
                raise PaymentException(data['responseText'])

            # To save the result
            payment.info = req.json()
            payment.confirm()
        except (HTTPError, PaymentException, Quota.QuotaExceededException):
            logger.exception('QPayPro error: %s' % req.text)
            try:
                payment.info_data = req.json()
            except Exception:
                payment.info_data = {'error': True, 'detail': req.text}
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action(
                'pretix.event.order.payment.failed', {
                    'local_id': payment.local_id,
                    'provider': payment.provider,
                    'data': payment.info_data
                })
            raise PaymentException(
                _('We had trouble communicating with QPayPro. Please try again and get in touch '
                  'with us if this problem persists.'))

        return None
예제 #5
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        self._init_api()
        try:
            source = self._create_source(request, payment)
        except stripe.error.StripeError as e:
            if e.json_body and 'err' in e.json_body:
                err = e.json_body['error']
                logger.exception('Stripe error: %s' % str(err))
            else:
                err = {'message': str(e)}
                logger.exception('Stripe error: %s' % str(e))
            payment.info_data = {
                'error': True,
                'message': err['message'],
            }
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action('pretix.event.order.payment.failed', {
                'local_id': payment.local_id,
                'provider': payment.provider,
                'message': err['message']
            })
            raise PaymentException(_('We had trouble communicating with Stripe. Please try again and get in touch '
                                     'with us if this problem persists.'))

        ReferencedStripeObject.objects.get_or_create(
            reference=source.id,
            defaults={'order': payment.order, 'payment': payment}
        )
        payment.info = str(source)
        payment.state = OrderPayment.PAYMENT_STATE_PENDING
        payment.save()
        request.session['payment_stripe_order_secret'] = payment.order.secret
        return self.redirect(request, source.redirect.url)
예제 #6
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        self._init_api()
        try:
            source = self._create_source(request, payment)
        except stripe.error.StripeError as e:
            if e.json_body:
                err = e.json_body['error']
                logger.exception('Stripe error: %s' % str(err))
            else:
                err = {'message': str(e)}
                logger.exception('Stripe error: %s' % str(e))
            payment.info_data = {
                'error': True,
                'message': err['message'],
            }
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action('pretix.event.order.payment.failed', {
                'local_id': payment.local_id,
                'provider': payment.provider,
                'message': err['message']
            })
            raise PaymentException(_('We had trouble communicating with Stripe. Please try again and get in touch '
                                     'with us if this problem persists.'))

        ReferencedStripeObject.objects.get_or_create(
            reference=source.id,
            defaults={'order': payment.order, 'payment': payment}
        )
        payment.info = str(source)
        payment.state = OrderPayment.PAYMENT_STATE_PENDING
        payment.save()
        request.session['payment_stripe_order_secret'] = payment.order.secret
        return self.redirect(request, source.redirect.url)
예제 #7
0
    def execute_payment(self, request: HttpRequest,
                        payment: OrderPayment) -> str:
        # This method will only be called when retrying payments, e.g. after a payment_prepare call. It is not called
        # during the order creation phase because this payment provider is a special case.
        for p in payment.order.positions.all():  # noqa - just a safeguard
            if p.item.issue_giftcard:
                raise PaymentException(
                    _("You cannot pay with gift cards when buying a gift card."
                      ))

        gcpk = payment.info_data.get('gift_card')
        if not gcpk or not payment.info_data.get('retry'):
            raise PaymentException("Invalid state, should never occur.")
        with transaction.atomic():
            gc = GiftCard.objects.select_for_update().get(pk=gcpk)
            if gc.currency != self.event.currency:  # noqa - just a safeguard
                raise PaymentException(
                    _("This gift card does not support this currency."))
            if not gc.accepted_by(
                    self.event.organizer):  # noqa - just a safeguard
                raise PaymentException(
                    _("This gift card is not accepted by this event organizer."
                      ))
            if payment.amount > gc.value:  # noqa - just a safeguard
                raise PaymentException(
                    _("This gift card was used in the meantime. Please try again"
                      ))
            trans = gc.transactions.create(value=-1 * payment.amount,
                                           order=payment.order,
                                           payment=payment)
            payment.info_data = {
                'gift_card': gc.pk,
                'transaction_id': trans.pk,
            }
            payment.confirm()
예제 #8
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        pay_data = {
            "NotificationURL": build_absolute_uri(self.event, 'plugins:pretix_tinkoff:webhook', kwargs={
                'payment': payment.pk
            }),
            "SuccessURL": build_absolute_uri(self.event, 'plugins:pretix_tinkoff:return', kwargs={
                'order': payment.order.code,
                'payment': payment.pk,
                'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
                'action': 'success'
            }),
            "FailURL": build_absolute_uri(self.event, 'plugins:pretix_tinkoff:return', kwargs={
                'order': payment.order.code,
                'payment': payment.pk,
                'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
                'action': 'fail'
            }),
            'Amount': int(payment.amount * 100),
            'OrderId': "{}-{}".format(self.event.slug.upper(), payment.order.code),
            'Description': "Order {}-{}".format(self.event.slug.upper(), payment.order.code),
            'DATA': {
                'organizer': self.event.organizer.slug,
                'event': self.event.slug,
                'order': payment.order.code,
                'payment': payment.local_id,
                'order-full-code': payment.order.full_code
            },
            'PayType': "O"
        }
        try:
            req = self._init(pay_data)
        except HTTPError:
            logger.exception('Tinkoff error: %s' % req)
        
        if req['Success'] == False:
            logger.exception('Tinkoff error: %s' % req)

            payment.info_data = {
                'error': True,
                'detail': req
            }
            
            payment.state = OrderPayment.PAYMENT_STATE_FAILED
            payment.save()
            payment.order.log_action('pretix.event.order.payment.failed', {
                'local_id': payment.local_id,
                'provider': payment.provider,
                'data': payment.info_data
            })
            raise PaymentException(_('We had trouble communicating with Tinkoff. Please try again and get in touch '
                                     'with us if this problem persists. Detail: {}'.format(req['Details'])))
        ReferencedTinkoffTransaction.objects.get_or_create(order=payment.order, payment=payment, reference=req['PaymentId'])
        LogTransaction(paymentid=req['PaymentId'], order=payment.order, payment=payment, method='get', meta_info=json.dumps(req))
        payment.info = json.dumps(req)
        payment.state = OrderPayment.PAYMENT_STATE_CREATED
        logger.info('pay_request: {}'.format(pay_data))
        logger.info('pay_response: {}'.format(payment.info))
        payment.save(update_fields=['info'])
        return self.redirect(request, req['PaymentURL'])
예제 #9
0
 def execute_payment(self, request: HttpRequest, payment: OrderPayment):
     request.session['sofort_order_secret'] = payment.order.secret
     shash = hashlib.sha1(payment.order.secret.lower().encode()).hexdigest()
     r = sofort.MultiPay(
         project_id=self.settings.get('project_id'),
         amount=payment.amount,
         currency_code=self.event.currency,
         reasons=[payment.order.full_code, '-TRANSACTION-'],
         user_variables=[payment.order.full_code],
         success_url=build_absolute_uri(self.event,
                                        'plugins:pretix_sofort:return',
                                        kwargs={
                                            'order': payment.order.code,
                                            'hash': shash,
                                        }) +
         '?state=success&transaction=-TRANSACTION-',
         abort_url=build_absolute_uri(self.event,
                                      'plugins:pretix_sofort:return',
                                      kwargs={
                                          'order': payment.order.code,
                                          'hash': shash,
                                      }) +
         '?state=abort&transaction=-TRANSACTION-',
         timeout_url=build_absolute_uri(self.event,
                                        'plugins:pretix_sofort:return',
                                        kwargs={
                                            'order': payment.order.code,
                                            'hash': shash,
                                        }) +
         '?state=timeout&transaction=-TRANSACTION-',
         notification_urls=[
             build_absolute_uri(self.event, 'plugins:pretix_sofort:webhook')
         ],
     )
     try:
         trans = sofort.NewTransaction.from_xml(self._api_call(r.to_xml()))
     except sofort.SofortError as e:
         logger.exception('Failure during sofort payment: {}'.format(
             e.message))
         raise PaymentException(
             _('Sofort reported an error: {}').format(e.message))
     except IOError:
         logger.exception('Failure during sofort payment.')
         raise PaymentException(
             _('We had trouble communicating with Sofort. Please try again and get in touch '
               'with us if this problem persists.'))
     ReferencedSofortTransaction.objects.get_or_create(
         order=payment.order, reference=trans.transaction, payment=payment)
     payment.info_data = {
         'transaction': trans.transaction,
         'status': 'initiated'
     }
     payment.save(update_fields=['info'])
     return self.redirect(request, trans.payment_url)
예제 #10
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        currency_type = request.session['payment_ethereum_currency_type']
        payment_timestamp = request.session['payment_ethereum_time']

        payment_amount = request.session['payment_ethereum_amount']

        payment.info_data = {
            'currency_type': currency_type,
            'time': payment_timestamp,
            'amount': payment_amount,
        }
        payment.save(update_fields=['info'])
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        currency_type = request.session['payment_ethereum_currency_type']
        payment_timestamp = request.session['payment_ethereum_time']

        truncated_amount_in_wei = request.session['payment_ethereum_amount']
        amount_plus_payment_id = truncated_amount_in_wei + payment.id

        payment.info_data = {
            'currency_type': currency_type,
            'time': payment_timestamp,
            'amount': amount_plus_payment_id,
        }
        payment.save(update_fields=['info'])
예제 #12
0
    def payment_prepare(self, request: HttpRequest,
                        payment: OrderPayment) -> Union[bool, str, None]:
        for p in payment.order.positions.all():
            if p.item.issue_giftcard:
                messages.error(
                    request,
                    _("You cannot pay with gift cards when buying a gift card."
                      ))
                return

        try:
            gc = self.event.organizer.accepted_gift_cards.get(
                secret=request.POST.get("giftcard"))
            if gc.currency != self.event.currency:
                messages.error(
                    request,
                    _("This gift card does not support this currency."))
                return
            if gc.testmode and not payment.order.testmode:
                messages.error(
                    request,
                    _("This gift card can only be used in test mode."))
                return
            if not gc.testmode and payment.order.testmode:
                messages.error(
                    request,
                    _("Only test gift cards can be used in test mode."))
                return
            if gc.value <= Decimal("0.00"):
                messages.error(
                    request, _("All credit on this gift card has been used."))
                return
            payment.info_data = {'gift_card': gc.pk, 'retry': True}
            payment.amount = min(payment.amount, gc.value)
            payment.save()

            return True
        except GiftCard.DoesNotExist:
            if self.event.vouchers.filter(
                    code__iexact=request.POST.get("giftcard")).exists():
                messages.warning(
                    request,
                    _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below "
                      "the product selection."))
            else:
                messages.error(request, _("This gift card is not known."))
        except GiftCard.MultipleObjectsReturned:
            messages.error(
                request,
                _("This gift card can not be redeemed since its code is not unique. Please contact the organizer of this event."
                  ))
예제 #13
0
 def execute_payment(self, request: HttpRequest, payment: OrderPayment):
     payment.info_data = {
         'sender_address': request.session['payment_ethereum_fm_address'],
         'currency': request.session['payment_ethereum_fm_currency'],
         'time': request.session['payment_ethereum_time'],
         'amount': request.session['payment_ethereum_amount'],
     }
     payment.save(update_fields=['info'])
     try:
         if request.session['payment_ethereum_fm_currency'] == 'ETH':
             response = requests.get(
                 f'https://api.ethplorer.io/getAddressTransactions/{self.settings.ETH}?apiKey=freekey'  # noqa: E501
             )
             deca = response.json()
             if len(deca) > 0:
                 for decc in deca:
                     if decc['success'] == True and decc[
                             'from'] == request.session[
                                 'payment_ethereum_fm_address']:  # noqa: E501
                         if decc['timestamp'] > request.session[
                                 'payment_ethereum_time'] and decc[
                                     'value'] >= request.session[
                                         'payment_ethereum_amount']:  # noqa: E501
                             try:
                                 payment.confirm()
                             except Quota.QuotaExceededException as e:
                                 raise PaymentException(str(e))
         else:
             dec = requests.get(
                 'https://blockscout.com/poa/dai/api?module=account&action=txlist&address='
                 + self.settings.DAI)  # noqa: E501
             deca = dec.json()
             for decc in deca['result']:
                 if decc['txreceipt_status'] == '1' and decc[
                         'from'] == request.session[
                             'payment_ethereum_fm_address']:  # noqa: E501
                     #           if (decc['timestamp'] > request.session['payment_ethereum_time'] and decc[  # noqa: E501
                     # 'value'] >= request.session['payment_ethereum_amount']):
                     try:
                         payment.confirm()
                     except Quota.QuotaExceededException as e:
                         raise PaymentException(str(e))
     except NameError:
         pass
     except TypeError:
         pass
     except AttributeError:
         pass
     return None
예제 #14
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        txn_hash = request.session['payment_ethereum_txn_hash']
        txn_hash_bytes = to_bytes(hexstr=txn_hash)
        currency_type = request.session['payment_ethereum_currency_type']
        payment_timestamp = request.session['payment_ethereum_time']
        payment_amount = request.session['payment_ethereum_amount']

        if Transaction.objects.filter(txn_hash=txn_hash_bytes).exists():
            raise PaymentException(
                f'Transaction with hash {txn_hash} already used for payment')

        payment.info_data = {
            'txn_hash': txn_hash,
            'currency_type': currency_type,
            'time': payment_timestamp,
            'amount': payment_amount,
        }
        payment.save(update_fields=['info'])

        if currency_type == 'ETH':
            transaction = self.transaction_provider.get_transaction(txn_hash)
            is_valid_payment = all((
                transaction.success,
                transaction.to == self.settings.ETH,
                transaction.value >= payment_amount,
                transaction.timestamp >= payment_timestamp,
            ))
        elif currency_type == 'DAI':
            transfer = self.token_provider.get_ERC20_transfer(txn_hash)
            is_valid_payment = all((
                transfer.success,
                transfer.to == self.settings.DAI,
                transfer.value >= payment_amount,
                transfer.timestamp >= payment_timestamp,
            ))
        else:
            # unkown currency
            raise ImproperlyConfigured(f"Unknown currency: {currency_type}")

        if is_valid_payment:
            with db_transaction.atomic():
                try:
                    payment.confirm()
                except Quota.QuotaExceededException as e:
                    raise PaymentException(str(e))
                else:
                    Transaction.objects.create(txn_hash=txn_hash_bytes,
                                               order_payment=payment)
예제 #15
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        due_date = self._due_date()
        ref = '%s-%s' % (self.event.slug.upper(), payment.order.code)
        if self.settings.reference_prefix:
            ref = self.settings.reference_prefix + "-" + ref

        try:
            payment.info_data = {
                'account': request.session['payment_sepa_account'],
                'iban': request.session['payment_sepa_iban'],
                'bic': request.session['payment_sepa_bic'],
                'reference': ref,
                'date': due_date.strftime("%Y-%m-%d")
            }
            payment.confirm(
                mail_text=self.order_pending_mail_render(payment.order))
        except Quota.QuotaExceededException as e:
            raise PaymentException(str(e))
        finally:
            del request.session['payment_sepa_account']
            del request.session['payment_sepa_iban']
            del request.session['payment_sepa_bic']
예제 #16
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        due_date, reminded = self._due_date_reminded()
        ref = '%s-%s' % (self.event.slug.upper(), payment.order.code)
        if self.settings.reference_prefix:
            ref = self.settings.reference_prefix + "-" + ref

        try:
            payment.info_data = {
                'account': request.session['payment_sepa_account'],
                'iban': request.session['payment_sepa_iban'],
                'bic': request.session['payment_sepa_bic'],
                'reference': ref,
            }

            # add current time to due_date for remind after to take pressure of the cron job
            due = SepaDueDate.objects.update_or_create(
                payment=payment,
                defaults={
                    'date':
                    due_date,
                    'reminded':
                    reminded,
                    'remind_after':
                    now().astimezone(self.event.timezone).replace(
                        year=due_date.year,
                        month=due_date.month,
                        day=due_date.day)
                })[0]

            payment.confirm(
                mail_text=self.order_pending_mail_render(payment.order))
        except Quota.QuotaExceededException as e:
            due.delete()
            raise PaymentException(str(e))
        finally:
            del request.session['payment_sepa_account']
            del request.session['payment_sepa_iban']
            del request.session['payment_sepa_bic']
예제 #17
0
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        self._init_api()

        if request.session['payment_stripe_token'].startswith('src_'):
            try:
                src = stripe.Source.retrieve(request.session['payment_stripe_token'], **self.api_kwargs)
                if src.type == 'card' and src.card and self._use_3ds(src.card):
                    request.session['payment_stripe_order_secret'] = payment.order.secret
                    source = stripe.Source.create(
                        type='three_d_secure',
                        amount=self._get_amount(payment),
                        currency=self.event.currency.lower(),
                        three_d_secure={
                            'card': src.id
                        },
                        statement_descriptor=ugettext('{event}-{code}').format(
                            event=self.event.slug.upper(),
                            code=payment.order.code
                        )[:22],
                        metadata={
                            'order': str(payment.order.id),
                            'event': self.event.id,
                            'code': payment.order.code
                        },
                        redirect={
                            'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
                                'order': payment.order.code,
                                'payment': payment.pk,
                                'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
                            })
                        },
                        **self.api_kwargs
                    )
                    ReferencedStripeObject.objects.get_or_create(
                        reference=source.id,
                        defaults={'order': payment.order, 'payment': payment}
                    )
                    if source.status == "pending":
                        payment.info = str(source)
                        payment.state = OrderPayment.PAYMENT_STATE_PENDING
                        payment.save()
                        return self.redirect(request, source.redirect.url)
            except stripe.error.StripeError as e:
                if e.json_body:
                    err = e.json_body['error']
                    logger.exception('Stripe error: %s' % str(err))
                else:
                    err = {'message': str(e)}
                    logger.exception('Stripe error: %s' % str(e))
                payment.info_data = {
                    'error': True,
                    'message': err['message'],
                }
                payment.state = OrderPayment.PAYMENT_STATE_FAILED
                payment.save()
                payment.order.log_action('pretix.event.order.payment.failed', {
                    'local_id': payment.local_id,
                    'provider': payment.provider,
                    'message': err['message']
                })
                raise PaymentException(_('We had trouble communicating with Stripe. Please try again and get in touch '
                                         'with us if this problem persists.'))

        try:
            self._charge_source(request, request.session['payment_stripe_token'], payment)
        finally:
            del request.session['payment_stripe_token']
예제 #18
0
파일: payment.py 프로젝트: obutuz/pretix
    def execute_payment(self, request: HttpRequest, payment: OrderPayment):
        self._init_api()

        if request.session['payment_stripe_token'].startswith('src_'):
            try:
                src = stripe.Source.retrieve(request.session['payment_stripe_token'], **self.api_kwargs)
                if src.type == 'card' and src.card and self._use_3ds(src.card):
                    request.session['payment_stripe_order_secret'] = payment.order.secret
                    source = stripe.Source.create(
                        type='three_d_secure',
                        amount=self._get_amount(payment),
                        currency=self.event.currency.lower(),
                        three_d_secure={
                            'card': src.id
                        },
                        statement_descriptor=ugettext('{event}-{code}').format(
                            event=self.event.slug.upper(),
                            code=payment.order.code
                        )[:22],
                        metadata={
                            'order': str(payment.order.id),
                            'event': self.event.id,
                            'code': payment.order.code
                        },
                        redirect={
                            'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
                                'order': payment.order.code,
                                'payment': payment.pk,
                                'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
                            })
                        },
                        **self.api_kwargs
                    )
                    ReferencedStripeObject.objects.get_or_create(
                        reference=source.id,
                        defaults={'order': payment.order, 'payment': payment}
                    )
                    if source.status == "pending":
                        payment.info = str(source)
                        payment.state = OrderPayment.PAYMENT_STATE_PENDING
                        payment.save()
                        return self.redirect(request, source.redirect.url)
            except stripe.error.StripeError as e:
                if e.json_body:
                    err = e.json_body['error']
                    logger.exception('Stripe error: %s' % str(err))
                else:
                    err = {'message': str(e)}
                    logger.exception('Stripe error: %s' % str(e))
                payment.info_data = {
                    'error': True,
                    'message': err['message'],
                }
                payment.state = OrderPayment.PAYMENT_STATE_FAILED
                payment.save()
                raise PaymentException(_('We had trouble communicating with Stripe. Please try again and get in touch '
                                         'with us if this problem persists.'))

        try:
            self._charge_source(request, request.session['payment_stripe_token'], payment)
        finally:
            del request.session['payment_stripe_token']