def charge_webhook(event, event_json, charge_id): prov = StripeCC(event) prov._init_api() try: charge = stripe.Charge.retrieve(charge_id) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = charge['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) try: order = event.orders.get(id=metadata['order'], payment_provider__startswith='stripe') except Order.DoesNotExist: return HttpResponse('Order not found', status=200) if order.payment_provider != prov.identifier: prov = event.get_payment_providers()[order.payment_provider] prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) is_refund = charge['refunds']['total_count'] or charge['dispute'] if order.status == Order.STATUS_PAID and is_refund: RequiredAction.objects.create( event=event, action_type='pretix.plugins.stripe.refund', data=json.dumps({ 'order': order.code, 'charge': charge_id })) elif order.status in ( Order.STATUS_PENDING, Order.STATUS_EXPIRED ) and charge['status'] == 'succeeded' and not is_refund: try: mark_order_paid(order, user=None) except LockTimeoutException: return HttpResponse("Lock timeout, please try again.", status=503) except Quota.QuotaExceededException: if not RequiredAction.objects.filter( event=event, action_type='pretix.plugins.stripe.overpaid', data__icontains=order.code).exists(): RequiredAction.objects.create( event=event, action_type='pretix.plugins.stripe.overpaid', data=json.dumps({ 'order': order.code, 'charge': charge.id })) return HttpResponse(status=200)
def paymentintent_webhook(event, event_json, paymentintent_id, rso): prov = StripeCC(event) prov._init_api() try: paymentintent = stripe.PaymentIntent.retrieve(paymentintent_id, **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) for charge in paymentintent.charges.data: ReferencedStripeObject.objects.get_or_create( reference=charge.id, defaults={'order': rso.payment.order, 'payment': rso.payment} ) return HttpResponse(status=200)
def source_webhook(event, event_json, source_id): prov = StripeCC(event) prov._init_api() try: src = stripe.Source.retrieve(source_id, **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = src['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) with transaction.atomic(): try: order = event.orders.get(id=metadata['order'], payment_provider__startswith='stripe') except Order.DoesNotExist: return HttpResponse('Order not found', status=200) if order.payment_provider != prov.identifier: prov = event.get_payment_providers()[order.payment_provider] prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) go = (event_json['type'] == 'source.chargeable' and order.status == Order.STATUS_PENDING and src.status == 'chargeable') if go: try: prov._charge_source(None, source_id, order) except PaymentException: logger.exception('Webhook error') return HttpResponse(status=200)
def source_webhook(event, event_json, source_id, rso): prov = StripeCC(event) prov._init_api() try: src = stripe.Source.retrieve(source_id, **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = src['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) with transaction.atomic(): if rso and rso.payment: order = rso.payment.order payment = rso.payment elif rso: order = rso.order payment = None else: try: order = event.orders.get(id=metadata['order']) except Order.DoesNotExist: return HttpResponse('Order not found', status=200) payment = None if not payment: payment = order.payments.filter( info__icontains=src['id'], provider__startswith='stripe', amount=prov._amount_to_decimal(src['amount']) if src['amount'] is not None else order.total, ).last() if not payment: payment = order.payments.create( state=OrderPayment.PAYMENT_STATE_CREATED, provider=SOURCE_TYPES.get(src['type'], 'stripe'), amount=prov._amount_to_decimal(src['amount']) if src['amount'] is not None else order.total, info=str(src), ) if payment.provider != prov.identifier: prov = payment.payment_provider prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) go = (event_json['type'] == 'source.chargeable' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED) and src.status == 'chargeable') if go: try: prov._charge_source(None, source_id, payment) except PaymentException: logger.exception('Webhook error') elif src.status == 'failed': payment.info = str(src) payment.state = OrderPayment.PAYMENT_STATE_FAILED payment.order.log_action('pretix.event.order.payment.failed', { 'local_id': payment.local_id, 'provider': payment.provider, 'info': str(src) }) payment.save() return HttpResponse(status=200)
def charge_webhook(event, event_json, charge_id, rso): prov = StripeCC(event) prov._init_api() try: charge = stripe.Charge.retrieve(charge_id, expand=['dispute'], **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = charge['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) if rso and rso.payment: order = rso.payment.order payment = rso.payment elif rso: order = rso.order payment = None else: try: order = event.orders.get(id=metadata['order']) except Order.DoesNotExist: return HttpResponse('Order not found', status=200) payment = None if not payment: payment = order.payments.filter( info__icontains=charge['id'], provider__startswith='stripe', amount=prov._amount_to_decimal(charge['amount']), ).last() if not payment: payment = order.payments.create( state=OrderPayment.PAYMENT_STATE_CREATED, provider=SOURCE_TYPES.get(charge['source'].get('type', charge['source'].get('object', 'card')), 'stripe'), amount=prov._amount_to_decimal(charge['amount']), info=str(charge), ) if payment.provider != prov.identifier: prov = payment.payment_provider prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) is_refund = charge['refunds']['total_count'] or charge['dispute'] if is_refund: known_refunds = [r.info_data.get('id') for r in payment.refunds.all()] migrated_refund_amounts = [r.amount for r in payment.refunds.all() if not r.info_data.get('id')] for r in charge['refunds']['data']: a = prov._amount_to_decimal(r['amount']) if r['status'] in ('failed', 'canceled'): continue if a in migrated_refund_amounts: migrated_refund_amounts.remove(a) continue if r['id'] not in known_refunds: payment.create_external_refund( amount=a, info=str(r) ) if charge['dispute']: if charge['dispute']['status'] != 'won' and charge['dispute']['id'] not in known_refunds: a = prov._amount_to_decimal(charge['dispute']['amount']) if a in migrated_refund_amounts: migrated_refund_amounts.remove(a) else: payment.create_external_refund( amount=a, info=str(charge['dispute']) ) elif charge['status'] == 'succeeded' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED): try: payment.confirm() except LockTimeoutException: return HttpResponse("Lock timeout, please try again.", status=503) except Quota.QuotaExceededException: pass elif charge['status'] == 'failed' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED): payment.info = str(charge) 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, 'info': str(charge) }) return HttpResponse(status=200)
def source_webhook(event, event_json, source_id, rso): prov = StripeCC(event) prov._init_api() try: src = stripe.Source.retrieve(source_id, **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = src['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) with transaction.atomic(): if rso and rso.payment: order = rso.payment.order payment = rso.payment elif rso: order = rso.order payment = None else: try: order = event.orders.get(id=metadata['order']) except Order.DoesNotExist: return HttpResponse('Order not found', status=200) payment = None if not payment: payment = order.payments.filter( info__icontains=src['id'], provider__startswith='stripe', amount=prov._amount_to_decimal(src['amount']) if src['amount'] is not None else order.total, ).last() if not payment: payment = order.payments.create( state=OrderPayment.PAYMENT_STATE_CREATED, provider=SOURCE_TYPES.get(src['type'], 'stripe'), amount=prov._amount_to_decimal(src['amount']) if src['amount'] is not None else order.total, info=str(src), ) if payment.provider != prov.identifier: prov = payment.payment_provider prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) go = (event_json['type'] == 'source.chargeable' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED) and src.status == 'chargeable') if go: try: prov._charge_source(None, source_id, payment) except PaymentException: logger.exception('Webhook error') elif src.status == 'failed': payment.info = str(src) payment.state = OrderPayment.PAYMENT_STATE_FAILED payment.order.log_action('pretix.event.order.payment.failed', { 'local_id': payment.local_id, 'provider': payment.provider, 'info': str(src) }) payment.save() elif src.status == 'canceled' and payment.state in (Order.STATUS_PENDING, OrderPayment.PAYMENT_STATE_CREATED): payment.info = str(src) payment.state = OrderPayment.PAYMENT_STATE_CANCELED payment.save() return HttpResponse(status=200)
def charge_webhook(event, event_json, charge_id, rso): prov = StripeCC(event) prov._init_api() try: charge = stripe.Charge.retrieve(charge_id, expand=['dispute'], **prov.api_kwargs) except stripe.error.StripeError: logger.exception('Stripe error on webhook. Event data: %s' % str(event_json)) return HttpResponse('Charge not found', status=500) metadata = charge['metadata'] if 'event' not in metadata: return HttpResponse('Event not given in charge metadata', status=200) if int(metadata['event']) != event.pk: return HttpResponse('Not interested in this event', status=200) if rso and rso.payment: order = rso.payment.order payment = rso.payment elif rso: order = rso.order payment = None else: try: order = event.orders.get(id=metadata['order']) except Order.DoesNotExist: return HttpResponse('Order not found', status=200) payment = None if not payment: payment = order.payments.filter( info__icontains=charge['id'], provider__startswith='stripe', amount=prov._amount_to_decimal(charge['amount']), ).last() if not payment: payment = order.payments.create( state=OrderPayment.PAYMENT_STATE_CREATED, provider=SOURCE_TYPES.get(charge['source'].get('type', charge['source'].get('object', 'card')), 'stripe'), amount=prov._amount_to_decimal(charge['amount']), info=str(charge), ) if payment.provider != prov.identifier: prov = payment.payment_provider prov._init_api() order.log_action('pretix.plugins.stripe.event', data=event_json) is_refund = charge['refunds']['total_count'] or charge['dispute'] if is_refund: known_refunds = [r.info_data.get('id') for r in payment.refunds.all()] migrated_refund_amounts = [r.amount for r in payment.refunds.all() if not r.info_data.get('id')] for r in charge['refunds']['data']: a = prov._amount_to_decimal(r['amount']) if r['status'] in ('failed', 'canceled'): continue if a in migrated_refund_amounts: migrated_refund_amounts.remove(a) continue if r['id'] not in known_refunds: payment.create_external_refund( amount=a, info=str(r) ) if charge['dispute']: if charge['dispute']['status'] != 'won' and charge['dispute']['id'] not in known_refunds: a = prov._amount_to_decimal(charge['dispute']['amount']) if a in migrated_refund_amounts: migrated_refund_amounts.remove(a) else: payment.create_external_refund( amount=a, info=str(charge['dispute']) ) elif charge['status'] == 'succeeded' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED): try: payment.confirm() except LockTimeoutException: return HttpResponse("Lock timeout, please try again.", status=503) except Quota.QuotaExceededException: pass elif charge['status'] == 'failed' and payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED): payment.info = str(charge) 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, 'info': str(charge) }) return HttpResponse(status=200)