def stripe_refund(order, event, payment_id, amount): stripe_prep(event.api_type) if event.api_type == LIVE: access_token = event.organization.stripe_access_token else: access_token = event.organization.stripe_test_access_token # Retrieving the charge and refunding it uses the access token. stripe.api_key = access_token charge = stripe.Charge.retrieve(payment_id) refund = charge.refunds.create( amount=int(amount * 100), refund_application_fee=True, expand=['balance_transaction'], metadata={ 'order': order.code, 'event': event.name, }, ) stripe_prep(event.api_type) try: application_fee = stripe.ApplicationFee.all(charge=charge).data[0] application_fee_refund = application_fee.refunds.data[0] except IndexError: raise Exception("No application fee refund found.") return { 'refund': refund, 'application_fee_refund': application_fee_refund, }
def stripe_charge(source, amount, order, event, customer=None): if amount < 0: raise InvalidAmountException('Cannot charge an amount less than zero.') stripe_prep(event.api_type) if event.api_type == LIVE: stripe_account = event.organization.stripe_user_id else: stripe_account = event.organization.stripe_test_user_id if customer is not None: source = stripe.Token.create( customer=customer, card=source, stripe_account=stripe_account, ) return stripe.Charge.create( amount=int(amount * 100), currency=event.currency, source=source, application_fee=int(get_fee(event, amount) * 100), expand=['balance_transaction'], metadata={ 'order': order.code, 'event': event.name, }, stripe_account=stripe_account, )
def test_charge__no_customer(self): event = EventFactory(api_type=TEST, application_fee_percent=Decimal('2.5')) order = OrderFactory(event=event) self.assertTrue(event.stripe_connected()) stripe_prep(TEST) stripe.api_key = event.organization.stripe_test_access_token token = stripe.Token.create(card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) charge = stripe_charge( token, amount=42.15, order=order, event=event, ) self.assertIsInstance(charge.balance_transaction, stripe.StripeObject) self.assertEqual(charge.balance_transaction.object, "balance_transaction") self.assertEqual(len(charge.balance_transaction.fee_details), 2) self.assertEqual(charge.metadata, { 'order': order.code, 'event': event.name }) txn = Transaction.from_stripe_charge(charge, api_type=event.api_type, event=event) # 42.15 * 0.025 = 1.05 self.assertEqual(txn.application_fee, Decimal('1.05')) # (42.15 * 0.029) + 0.30 = 1.52 self.assertEqual(txn.processing_fee, Decimal('1.52')) refund = stripe_refund(order=order, event=event, payment_id=txn.remote_id, amount=txn.amount) self.assertEqual(refund['refund'].metadata, { 'order': order.code, 'event': event.name }) refund_txn = Transaction.from_stripe_refund(refund, api_type=event.api_type, related_transaction=txn, event=event) self.assertEqual(refund_txn.amount, -1 * txn.amount) self.assertEqual(refund_txn.application_fee, -1 * txn.application_fee) self.assertEqual(refund_txn.processing_fee, -1 * txn.processing_fee)
def stripe_organization_oauth_url(organization, api_type, request): stripe_prep(api_type) if api_type == LIVE: client_id = getattr(settings, 'STRIPE_APPLICATION_ID', None) else: client_id = getattr(settings, 'STRIPE_TEST_APPLICATION_ID', None) if not client_id: return '' redirect_uri = request.build_absolute_uri(reverse('brambling_stripe_connect')) base_url = "https://connect.stripe.com/oauth/authorize?client_id={client_id}&response_type=code&scope=read_write&state={state}&redirect_uri={redirect_uri}" return base_url.format(client_id=client_id, state="{}|{}".format(organization.slug, api_type), redirect_uri=urllib.quote(redirect_uri))
def setUp(self): stripe_prep(TEST) self.event = EventFactory() self.order = OrderFactory() self.factory = RequestFactory() self.view = StripeWebhookView.as_view() self.data = json.dumps({'id': 'evt_123_event_id'}) self.request = self.factory.post(path='/', content_type='application/json', data=self.data)
def test_charge__customer(self): event = EventFactory(api_type=TEST, application_fee_percent=Decimal('2.5')) order = OrderFactory(event=event) self.assertTrue(event.stripe_connected()) stripe_prep(TEST) token = stripe.Token.create( card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) customer = stripe.Customer.create( source=token, ) source = customer.default_source charge = stripe_charge( source, amount=42.15, event=event, order=order, customer=customer ) self.assertIsInstance(charge.balance_transaction, stripe.StripeObject) self.assertEqual(charge.balance_transaction.object, "balance_transaction") self.assertEqual(len(charge.balance_transaction.fee_details), 2) self.assertEqual(charge.metadata, {'order': order.code, 'event': event.name}) txn = Transaction.from_stripe_charge(charge, api_type=event.api_type, event=event) # 42.15 * 0.025 = 1.05 self.assertEqual(txn.application_fee, Decimal('1.05')) # (42.15 * 0.029) + 0.30 = 1.52 self.assertEqual(txn.processing_fee, Decimal('1.52')) refund = stripe_refund( order=order, event=event, payment_id=txn.remote_id, amount=txn.amount ) self.assertEqual(refund['refund'].metadata, {'order': order.code, 'event': event.name}) refund_txn = Transaction.from_stripe_refund(refund, api_type=event.api_type, related_transaction=txn, event=event) self.assertEqual(refund_txn.amount, -1 * txn.amount) self.assertEqual(refund_txn.application_fee, -1 * txn.application_fee) self.assertEqual(refund_txn.processing_fee, -1 * txn.processing_fee)
def test_add_card(self): stripe_prep(TEST) token = stripe.Token.create(card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) customer = stripe.Customer.create() self.assertEqual(customer.sources.total_count, 0) card = stripe_add_card(customer, token, TEST) customer = stripe.Customer.retrieve(customer.id) self.assertEqual(customer.sources.total_count, 1) stripe_delete_card(customer, card.id) customer = stripe.Customer.retrieve(customer.id) self.assertEqual(customer.sources.total_count, 0)
def setUp(self): stripe_prep(TEST) self.event = EventFactory() self.order = OrderFactory(event=self.event) self.factory = RequestFactory() self.view = StripeWebhookView.as_view() self.stripe_event = {'id': 'evt_123_event_id'} self.data = json.dumps(self.stripe_event) self.request = self.factory.post(path='/', content_type='application/json', data=self.data) item = ItemFactory(event=self.event) item_option = ItemOptionFactory(price=60, item=item) self.order.add_to_cart(item_option) token = stripe.Token.create( card={ 'number': '4242424242424242', 'exp_month': 12, 'exp_year': 2017, 'cvc': '123' }, ) charge = stripe_charge(token, 100, self.order, self.event) self.txn = Transaction.from_stripe_charge( charge, event=self.event, order=self.order, api_type=self.event.api_type, ) self.refund = stripe_refund(self.order, self.event, charge.id, 100) data = mock.Mock(object=mock.Mock(name='charge', id=charge.id)) self.mock_event = mock.Mock( data=data, type='charge.refunded', livemode=False, ) self.order.mark_cart_paid(self.txn)
def test_charge__negative_amount(self): event = EventFactory(api_type=TEST, application_fee_percent=Decimal('2.5')) order = OrderFactory(event=event) stripe_prep(TEST) stripe.api_key = event.organization.stripe_test_access_token token = stripe.Token.create( card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) with self.assertRaises(InvalidAmountException): stripe_charge(token, amount=Decimal('-9.01'), order=order, event=event)
def test_charge__negative_amount(self): event = EventFactory(api_type=TEST, application_fee_percent=Decimal('2.5')) order = OrderFactory(event=event) stripe_prep(TEST) stripe.api_key = event.organization.stripe_test_access_token token = stripe.Token.create(card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) with self.assertRaises(InvalidAmountException): stripe_charge(token, amount=Decimal('-9.01'), order=order, event=event)
def test_add_card(self): stripe_prep(TEST) token = stripe.Token.create( card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) customer = stripe.Customer.create() self.assertEqual(customer.sources.total_count, 0) card = stripe_add_card(customer, token, TEST) customer = stripe.Customer.retrieve(customer.id) self.assertEqual(customer.sources.total_count, 1) stripe_delete_card(customer, card.id) customer = stripe.Customer.retrieve(customer.id) self.assertEqual(customer.sources.total_count, 0)
def setUp(self): stripe_prep(TEST) self.event = EventFactory() self.order = OrderFactory(event=self.event) self.factory = RequestFactory() self.view = StripeWebhookView.as_view() self.stripe_event = {'id': 'evt_123_event_id'} self.data = json.dumps(self.stripe_event) self.request = self.factory.post(path='/', content_type='application/json', data=self.data) item = ItemFactory(event=self.event) item_option = ItemOptionFactory(price=60, item=item) self.order.add_to_cart(item_option) token = stripe.Token.create(card={ 'number': '4242424242424242', 'exp_month': 12, 'exp_year': 2017, 'cvc': '123' }, ) charge = stripe_charge(token, 100, self.order, self.event) self.txn = Transaction.from_stripe_charge( charge, event=self.event, order=self.order, api_type=self.event.api_type, ) self.refund = stripe_refund(self.order, self.event, charge.id, 100) data = mock.Mock(object=mock.Mock(name='charge', id=charge.id)) self.mock_event = mock.Mock( data=data, type='charge.refunded', livemode=False, ) self.order.mark_cart_paid(self.txn)
def stripe_get_customer(user, api_type, create=True): stripe_prep(api_type) if api_type == LIVE: customer_attr = 'stripe_customer_id' else: customer_attr = 'stripe_test_customer_id' customer_id = getattr(user, customer_attr) if not customer_id: if not create: return None customer = stripe.Customer.create( email=user.email, description=user.get_full_name(), metadata={'brambling_id': user.id}, ) setattr(user, customer_attr, customer.id) user.save() else: customer = stripe.Customer.retrieve(customer_id) return customer
def stripe_get_customer(user, api_type, create=True): stripe_prep(api_type) if api_type == LIVE: customer_attr = 'stripe_customer_id' else: customer_attr = 'stripe_test_customer_id' customer_id = getattr(user, customer_attr) if not customer_id: if not create: return None customer = stripe.Customer.create( email=user.email, description=user.get_full_name(), metadata={ 'brambling_id': user.id }, ) setattr(user, customer_attr, customer.id) user.save() else: customer = stripe.Customer.retrieve(customer_id) return customer
def post(self, request): if request.META['CONTENT_TYPE'] != 'application/json': raise Http404('Incorrect content type') try: event_data = json.loads(request.body) except ValueError: raise Http404('Webhook failed to decode request body') stripe_event_id = event_data.get('id') if not stripe_event_id: raise Http404('Event does not have an id') if event_data.get('livemode', False): stripe_prep(LIVE) else: stripe_prep(TEST) try: event = stripe.Event.retrieve(stripe_event_id) except stripe.error.InvalidRequestError: raise Http404('Event not found on stripe') if event.type != 'charge.refunded': return HttpResponse(status=200) if event.livemode: api_type = ProcessedStripeEvent.LIVE else: api_type = ProcessedStripeEvent.TEST _, new_event = ProcessedStripeEvent.objects.get_or_create( api_type=api_type, stripe_event_id=stripe_event_id, ) if not new_event: return HttpResponse(status=200) try: charge_id = event.data.object.id txn = Transaction.objects.get( remote_id=charge_id, api_type=api_type, ) except Transaction.DoesNotExist: return HttpResponse(status=200) except AttributeError: raise Http404('Charge id not found') event = txn.event if event.api_type == LIVE: access_token = event.organization.stripe_access_token else: access_token = event.organization.stripe_test_access_token stripe.api_key = access_token try: charge = stripe.Charge.retrieve( charge_id, expand=[ 'balance_transaction', 'application_fee', 'refunds.balance_transaction', ], ) except stripe.error.InvalidRequestError: raise Http404('Charge not found on stripe') for refund in charge.refunds: if Transaction.objects.filter( transaction_type=Transaction.REFUND, method=Transaction.STRIPE, remote_id=refund.id, related_transaction=txn, ).exists(): continue application_fee_refund = charge.application_fee.refunds.data[0] refund_group = { 'refund': refund, 'application_fee_refund': application_fee_refund, } refund_kwargs = { 'order': txn.order, 'related_transaction': txn, 'api_type': txn.api_type, 'event': txn.event, } Transaction.from_stripe_refund(refund_group, **refund_kwargs) return HttpResponse(status=200)
def setUp(self): stripe_prep(TEST) self.factory = RequestFactory() self.view = StripeWebhookView.as_view()
def stripe_add_card(customer, token, api_type): stripe_prep(api_type) return customer.sources.create(source=token)
def test_partial_refunds(self): event = EventFactory(api_type=TEST, application_fee_percent=Decimal('2.5')) order = OrderFactory(event=event) self.assertTrue(event.stripe_connected()) stripe_prep(TEST) stripe.api_key = event.organization.stripe_test_access_token token = stripe.Token.create( card={ "number": '4242424242424242', "exp_month": 12, "exp_year": 2050, "cvc": '123' }, ) charge = stripe_charge( token, amount=42.15, order=order, event=event, ) self.assertIsInstance(charge.balance_transaction, stripe.StripeObject) self.assertEqual(charge.balance_transaction.object, "balance_transaction") self.assertEqual(len(charge.balance_transaction.fee_details), 2) self.assertEqual(charge.metadata, {'order': order.code, 'event': event.name}) txn = Transaction.from_stripe_charge(charge, api_type=event.api_type, event=event) # 42.15 * 0.025 = 1.05 self.assertEqual(txn.application_fee, Decimal('1.05')) # (42.15 * 0.029) + 0.30 = 1.52 self.assertEqual(txn.processing_fee, Decimal('1.52')) refund1_amount = 10 refund1 = stripe_refund( order=order, event=event, payment_id=txn.remote_id, amount=refund1_amount ) self.assertEqual(refund1['refund'].metadata, {'order': order.code, 'event': event.name}) refund1_txn = Transaction.from_stripe_refund(refund1, api_type=event.api_type, related_transaction=txn, event=event) self.assertEqual(refund1_txn.amount, Decimal('-10.00')) # 10.00 * 0.025 = 0.25 self.assertEqual(refund1_txn.application_fee, Decimal('-0.25')) # 10.00 * 0.029 = 0.29 self.assertEqual(refund1_txn.processing_fee, Decimal('-0.29')) refund2_amount = 20 refund2 = stripe_refund( order=order, event=event, payment_id=txn.remote_id, amount=refund2_amount ) self.assertEqual(refund2['refund'].metadata, {'order': order.code, 'event': event.name}) refund2_txn = Transaction.from_stripe_refund(refund2, api_type=event.api_type, related_transaction=txn, event=event) self.assertEqual(refund2_txn.amount, Decimal('-20.00')) # 20.00 * 0.025 = 0.50 self.assertEqual(refund2_txn.application_fee, Decimal('-0.50')) # 20.00 * 0.029 = 0.58 self.assertEqual(refund2_txn.processing_fee, Decimal('-0.58'))