66from django .http import HttpResponse
77from django .utils .translation import gettext_lazy as _
88
9+ from drf_yasg import openapi
10+ from drf_yasg .utils import swagger_auto_schema
911from rest_framework import mixins , pagination , permissions , viewsets
1012from rest_framework .decorators import action
1113from rest_framework .exceptions import ValidationError as DRFValidationError
1416
1517from joanie .core import models
1618from joanie .core .enums import ORDER_STATE_PENDING
19+ from joanie .core .viewsets import (
20+ RequestResponseSerializersViewSetMixin ,
21+ ActionSerializerType ,
22+ )
1723from joanie .payment import get_payment_backend
1824from joanie .payment .models import Invoice
1925
@@ -111,6 +117,12 @@ def get_serializer_context(self):
111117
112118 return context
113119
120+ @swagger_auto_schema (
121+ query_serializer = serializers .ProductRetrieveQuerySerializer ,
122+ )
123+ def retrieve (self , * args , ** kwargs ):
124+ return super ().retrieve (* args , ** kwargs )
125+
114126
115127# pylint: disable=too-many-ancestors
116128class EnrollmentViewSet (
@@ -141,6 +153,7 @@ def perform_create(self, serializer):
141153
142154# pylint: disable=too-many-ancestors
143155class OrderViewSet (
156+ RequestResponseSerializersViewSetMixin ,
144157 mixins .ListModelMixin ,
145158 mixins .RetrieveModelMixin ,
146159 mixins .CreateModelMixin ,
@@ -163,6 +176,12 @@ class OrderViewSet(
163176 pagination_class = Pagination
164177 permission_classes = [permissions .IsAuthenticated ]
165178 serializer_class = serializers .OrderSerializer
179+ action_serializers = {
180+ "create" : {
181+ "request" : serializers .OrderCreateSerializer ,
182+ "response" : serializers .OrderCreateResponseSerializer ,
183+ }
184+ }
166185 filterset_class = filters .OrderViewSetFilter
167186 ordering = ["-created_on" ]
168187
@@ -171,21 +190,23 @@ def get_queryset(self):
171190 user = User .update_or_create_from_request_user (request_user = self .request .user )
172191 return user .orders .all ().select_related ("owner" , "product" , "certificate" )
173192
174- def perform_create (self , serializer ):
193+ def perform_create (self , validated_data ):
175194 """Force the order's "owner" field to the logged-in user."""
176195 owner = User .update_or_create_from_request_user (request_user = self .request .user )
177- serializer .save (owner = owner )
196+ print (">>>> owner" , owner )
197+ return models .Order .objects .create (** validated_data , owner = owner )
178198
179199 @transaction .atomic
180200 def create (self , request , * args , ** kwargs ):
181201 """Try to create an order and a related payment if the payment is fee."""
182- serializer = self .get_serializer (data = request .data )
202+ serializer = self .get_request_serializer (data = request .data )
183203 if not serializer .is_valid ():
184204 return Response (serializer .errors , status = 400 )
185205
186206 product = serializer .validated_data .get ("product" )
187207 course = serializer .validated_data .get ("course" )
188- billing_address = serializer .initial_data .get ("billing_address" )
208+ billing_address = serializer .validated_data .get ("billing_address" )
209+ credit_card_id = serializer .validated_data .get ("credit_card_id" )
189210
190211 # Populate organization field if it is not set and there is only one
191212 # on the product
@@ -210,7 +231,13 @@ def create(self, request, *args, **kwargs):
210231
211232 # - Validate data then create an order
212233 try :
213- self .perform_create (serializer )
234+ order_validated_data = {** serializer .validated_data }
235+ if billing_address :
236+ order_validated_data .pop ("billing_address" )
237+ if credit_card_id :
238+ order_validated_data .pop ("credit_card_id" )
239+ # FIXME this pop stuff should be done in OrderCreateSerializer.save
240+ order = self .perform_create (order_validated_data )
214241 except (DRFValidationError , IntegrityError ):
215242 return Response (
216243 (
@@ -222,12 +249,10 @@ def create(self, request, *args, **kwargs):
222249
223250 # Once order has been created, if product is not free, create a payment
224251 if product .price .amount > 0 :
225- order = serializer .instance
226252 payment_backend = get_payment_backend ()
227- credit_card_id = serializer .initial_data .get ("credit_card_id" )
228-
229253 # if payment in one click
230254 if credit_card_id :
255+ print ("payment info 3" )
231256 try :
232257 credit_card = CreditCard .objects .get (
233258 owner = order .owner , id = credit_card_id
@@ -241,18 +266,27 @@ def create(self, request, *args, **kwargs):
241266 except (CreditCard .DoesNotExist , NotImplementedError ):
242267 pass
243268 else :
269+ print ("payment info 2" )
244270 payment_info = payment_backend .create_payment (
245271 request = request , order = order , billing_address = billing_address
246272 )
247273
248- # Return the fresh new order with payment_info
249- return Response (
250- {** serializer .data , "payment_info" : payment_info }, status = 201
274+ response_serializer = self .get_response_serializer (
275+ instance = order ,
276+ context = {
277+ "payment_info" : payment_info ,
278+ },
251279 )
252-
280+ return Response (response_serializer .data , status = 201 )
281+ print ("payment info None" )
253282 # Else return the fresh new order
254- return Response (serializer .data , status = 201 )
283+ response_serializer = self .get_response_serializer (instance = order )
284+ return Response (response_serializer .data , status = 201 )
255285
286+ @swagger_auto_schema (
287+ request_body = serializers .OrderAbortBodySerializer ,
288+ responses = {204 : serializers .EmptyResponseSerializer },
289+ )
256290 @action (detail = True , methods = ["POST" ])
257291 def abort (self , request , pk = None ): # pylint: disable=no-self-use, invalid-name
258292 """Abort a pending order and the related payment if there is one."""
@@ -277,6 +311,17 @@ def abort(self, request, pk=None): # pylint: disable=no-self-use, invalid-name
277311
278312 return Response (status = 204 )
279313
314+ @swagger_auto_schema (
315+ query_serializer = serializers .OrderInvoiceQuerySerializer ,
316+ responses = {
317+ 200 : openapi .Response (
318+ "File Attachment" , schema = openapi .Schema (type = openapi .TYPE_FILE )
319+ ),
320+ 400 : serializers .ErrorResponseSerializer ,
321+ 404 : serializers .ErrorResponseSerializer ,
322+ },
323+ produces = "application/pdf" ,
324+ )
280325 @action (detail = True , methods = ["GET" ])
281326 def invoice (self , request , pk = None ): # pylint: disable=no-self-use, invalid-name
282327 """
@@ -391,6 +436,16 @@ def get_queryset(self):
391436 user = User .update_or_create_from_request_user (request_user = self .request .user )
392437 return models .Certificate .objects .filter (order__owner = user )
393438
439+ @swagger_auto_schema (
440+ responses = {
441+ 200 : openapi .Response (
442+ "File Attachment" , schema = openapi .Schema (type = openapi .TYPE_FILE )
443+ ),
444+ 404 : serializers .ErrorResponseSerializer ,
445+ 422 : serializers .ErrorResponseSerializer ,
446+ },
447+ produces = "application/pdf" ,
448+ )
394449 @action (detail = True , methods = ["GET" ])
395450 def download (self , request , pk = None ): # pylint: disable=no-self-use, invalid-name
396451 """
0 commit comments