Skip to content
This repository was archived by the owner on Oct 7, 2023. It is now read-only.

Commit a077165

Browse files
author
Mohammed Hammoud
committed
Add necessary API views
1 parent 2a523dd commit a077165

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed

payments/api/views.py

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
from django.shortcuts import get_object_or_404
2+
from django.core.exceptions import ObjectDoesNotExist
3+
from django.conf import settings
4+
from django.utils.encoding import smart_str
5+
6+
from rest_framework import status, generics
7+
from rest_framework.views import APIView
8+
from rest_framework.response import Response
9+
from rest_framework.permissions import IsAuthenticated
10+
11+
from .. import settings as app_settings
12+
13+
from .serializers import (
14+
CurrentSubscriptionSerializer,
15+
CurrentCustomerSerializer,
16+
SubscriptionSerializer,
17+
CardSerializer,
18+
CancelSerializer,
19+
ChargeSerializer,
20+
InvoiceSerializer,
21+
EventSerializer,
22+
WebhookSerializer,
23+
EventProcessingExceptionSerializer
24+
)
25+
26+
from ..models import (
27+
Event,
28+
Customer,
29+
CurrentSubscription,
30+
EventProcessingException
31+
)
32+
33+
import stripe
34+
35+
stripe.api_key = app_settings.get_api_key()
36+
37+
38+
class StripeView(APIView):
39+
""" Generic API StripeView """
40+
permission_classes = (IsAuthenticated, )
41+
42+
def get_current_subscription(self):
43+
try:
44+
return self.request.user.customer.current_subscription
45+
except CurrentSubscription.DoesNotExist:
46+
return None
47+
48+
def get_customer(self):
49+
try:
50+
return self.request.user.customer
51+
except ObjectDoesNotExist:
52+
return Customer.create(self.request.user)
53+
54+
55+
class CurrentCustomerDetailView(StripeView, generics.RetrieveAPIView):
56+
""" See the current customer/user payment details """
57+
58+
serializer_class = CurrentCustomerSerializer
59+
60+
def get_object(self):
61+
return self.get_customer()
62+
63+
64+
class SubscriptionView(StripeView):
65+
""" See, change/set the current customer/user subscription plan """
66+
serializer_class = SubscriptionSerializer
67+
68+
def get(self, request, *args, **kwargs):
69+
current_subscription = self.get_current_subscription()
70+
serializer = CurrentSubscriptionSerializer(current_subscription)
71+
return Response(serializer.data, status=status.HTTP_200_OK)
72+
73+
def post(self, request, *args, **kwargs):
74+
try:
75+
serializer = self.serializer_class(data=request.data)
76+
77+
if serializer.is_valid():
78+
validated_data = serializer.validated_data
79+
stripe_plan = validated_data.get('stripe_plan', None)
80+
customer = self.get_customer()
81+
subscription = customer.subscribe(stripe_plan)
82+
83+
return Response(subscription, status=status.HTTP_201_CREATED)
84+
else:
85+
return Response(serializer.errors)
86+
except stripe.StripeError as e:
87+
from django.utils.encoding import smart_str
88+
89+
error_data = {u'error': smart_str(e) or u'Unknown error'}
90+
return Response(error_data, status=status.HTTP_400_BAD_REQUEST)
91+
92+
93+
class ChangeCardView(StripeView):
94+
""" Add or update customer card details """
95+
serializer_class = CardSerializer
96+
97+
def post(self, request, *args, **kwargs):
98+
try:
99+
serializer = self.serializer_class(data=request.data)
100+
101+
if serializer.is_valid():
102+
validated_data = serializer.validated_data
103+
104+
customer = self.get_customer()
105+
card_token_response = customer.create_card_token(validated_data)
106+
token = card_token_response[0].get('id', None)
107+
customer.update_card(token)
108+
send_invoice = customer.card_fingerprint == ""
109+
110+
if send_invoice:
111+
customer.send_invoice()
112+
customer.retry_unpaid_invoices()
113+
114+
return Response(validated_data, status=status.HTTP_201_CREATED)
115+
else:
116+
return Response(serializer.errors)
117+
118+
except stripe.CardError as e:
119+
error_data = {u'error': smart_str(e) or u'Unknown error'}
120+
return Response(error_data, status=status.HTTP_400_BAD_REQUEST)
121+
122+
123+
class CancelView(StripeView):
124+
""" Cancel customer subscription """
125+
serializer_class = CancelSerializer
126+
127+
def post(self, request, *args, **kwargs):
128+
try:
129+
serializer = self.serializer_class(data=request.data)
130+
if serializer.is_valid():
131+
customer = self.get_customer()
132+
customer.cancel()
133+
return Response({'success': True}, status=status.HTTP_202_ACCEPTED)
134+
else:
135+
return Response(serializer.errors)
136+
except stripe.StripeError as e:
137+
error_data = {u'error': smart_str(e) or u'Unknown error'}
138+
return Response(error_data, status=status.HTTP_400_BAD_REQUEST)
139+
140+
141+
class PlanListView(StripeView):
142+
""" List all current plans """
143+
144+
def get(self, request, *args, **kwargs):
145+
return Response(settings.PAYMENTS_PLANS, status=status.HTTP_200_OK)
146+
147+
148+
class ChargeListView(StripeView, generics.ListAPIView):
149+
""" List customer charges """
150+
serializer_class = ChargeSerializer
151+
152+
def get_queryset(self):
153+
customer = self.get_customer()
154+
charges = customer.charges.all()
155+
return charges
156+
157+
158+
class InvoiceListView(StripeView, generics.ListAPIView):
159+
""" List customer invoices """
160+
serializer_class = InvoiceSerializer
161+
162+
def get_queryset(self):
163+
customer = self.get_customer()
164+
invoices = customer.invoices.all()
165+
return invoices
166+
167+
168+
class EventListView(StripeView, generics.ListAPIView):
169+
""" List customer events """
170+
serializer_class = EventSerializer
171+
172+
def get_queryset(self):
173+
customer = self.get_customer()
174+
events = customer.event_set.all()
175+
return events
176+
177+
178+
class WebhookView(StripeView):
179+
serializer_class = WebhookSerializer
180+
181+
def validate_webhook(self, webhook_data):
182+
webhook_id = webhook_data.get('id', None)
183+
webhook_type = webhook_data.get('type', None)
184+
webhook_livemode = webhook_data.get('livemode', None)
185+
is_valid = False
186+
187+
if webhook_id and webhook_type and webhook_livemode:
188+
is_valid = True
189+
return is_valid, webhook_id, webhook_type, webhook_livemode
190+
191+
def post(self, request, *args, **kwargs):
192+
try:
193+
serializer = self.serializer_class(data=request.data)
194+
195+
if serializer.is_valid():
196+
validated_data = serializer.validated_data
197+
webhook_data = validated_data.get('data', None)
198+
199+
is_webhook_valid, webhook_id, webhook_type, webhook_livemode = self.validate_webhook(webhook_data)
200+
201+
if is_webhook_valid:
202+
if Event.objects.filter(stripe_id=webhook_id).exists():
203+
obj = EventProcessingException.objects.create(
204+
data=validated_data,
205+
message="Duplicate event record",
206+
traceback=""
207+
)
208+
209+
event_processing_exception_serializer = EventProcessingExceptionSerializer(obj)
210+
return Response(event_processing_exception_serializer.data, status=status.HTTP_200_OK)
211+
else:
212+
event = Event.objects.create(
213+
stripe_id=webhook_id,
214+
kind=webhook_type,
215+
livemode=webhook_livemode,
216+
webhook_message=validated_data
217+
)
218+
event.validate()
219+
event.process()
220+
event_serializer = EventSerializer(event)
221+
return Response(event_serializer.data, status=status.HTTP_200_OK)
222+
else:
223+
error_data = {u'error': u'Webhook must contain id, type and livemode.'}
224+
return Response(error_data, status=status.HTTP_400_BAD_REQUEST)
225+
else:
226+
return Response(serializer.errors)
227+
except stripe.StripeError as e:
228+
error_data = {u'error': smart_str(e) or u'Unknown error'}
229+
return Response(error_data, status=status.HTTP_400_BAD_REQUEST)

0 commit comments

Comments
 (0)