Commit 47cd0f3e by asadiqbal08

EX-81 / Ex-84 changes

parent 7225420f
......@@ -9,6 +9,7 @@ from django.utils.translation import ugettext as _
from util.json_request import JsonResponse
from django.http import HttpResponse, HttpResponseNotFound
from shoppingcart.models import Coupon, CourseRegistrationCode
from opaque_keys.edx.locations import SlashSeparatedCourseKey
import logging
......@@ -54,32 +55,34 @@ def add_coupon(request, course_id): # pylint: disable=W0613
code = request.POST.get('code')
# check if the code is already in the Coupons Table and active
coupon = Coupon.objects.filter(is_active=True, code=code)
if coupon:
return HttpResponseNotFound(_("coupon with the coupon code ({code}) already exist").format(code=code))
# check if the coupon code is in the CourseRegistrationCode Table
course_registration_code = CourseRegistrationCode.objects.filter(code=code)
if course_registration_code:
return HttpResponseNotFound(_(
"The code ({code}) that you have tried to define is already in use as a registration code").format(code=code)
try:
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
coupon = Coupon.objects.get(is_active=True, code=code, course_id=course_id)
except Coupon.DoesNotExist:
# check if the coupon code is in the CourseRegistrationCode Table
course_registration_code = CourseRegistrationCode.objects.filter(code=code)
if course_registration_code:
return HttpResponseNotFound(_(
"The code ({code}) that you have tried to define is already in use as a registration code").format(code=code)
)
description = request.POST.get('description')
course_id = request.POST.get('course_id')
try:
discount = int(request.POST.get('discount'))
except ValueError:
return HttpResponseNotFound(_("Please Enter the Integer Value for Coupon Discount"))
if discount > 100 or discount < 0:
return HttpResponseNotFound(_("Please Enter the Coupon Discount Value Less than or Equal to 100"))
coupon = Coupon(
code=code, description=description, course_id=course_id,
percentage_discount=discount, created_by_id=request.user.id
)
coupon.save()
return HttpResponse(_("coupon with the coupon code ({code}) added successfully").format(code=code))
description = request.POST.get('description')
course_id = request.POST.get('course_id')
try:
discount = int(request.POST.get('discount'))
except ValueError:
return HttpResponseNotFound(_("Please Enter the Integer Value for Coupon Discount"))
if discount > 100:
return HttpResponseNotFound(_("Please Enter the Coupon Discount Value Less than or Equal to 100"))
coupon = Coupon(
code=code, description=description, course_id=course_id,
percentage_discount=discount, created_by_id=request.user.id
)
coupon.save()
return HttpResponse(_("coupon with the coupon code ({code}) added successfully").format(code=code))
if coupon:
return HttpResponseNotFound(_("coupon with the coupon code ({code}) already exists for this course").format(code=code))
@require_POST
......
......@@ -81,7 +81,7 @@ def purchase_transactions(course_id, features):
]
"""
purchased_courses = PaidCourseRegistration.objects.filter(course_id=course_id, status='purchased')
purchased_courses = PaidCourseRegistration.objects.filter(course_id=course_id, status='purchased').order_by('user')
def purchase_transactions_info(purchased_course, features):
""" convert purchase transactions to dictionary """
......@@ -103,12 +103,17 @@ def purchase_transactions(course_id, features):
for feature in order_item_features)
order_item_dict.update({"orderitem_id": getattr(purchased_course, 'id')})
try:
coupon_redemption = CouponRedemption.objects.select_related('coupon').get(order_id=purchased_course.order_id)
except CouponRedemption.DoesNotExist:
coupon_code_dict = {'coupon_code': 'None'}
coupon_redemption = CouponRedemption.objects.select_related('coupon').filter(order_id=purchased_course.order_id)
if coupon_redemption:
# we format the coupon codes in comma separated way if there are more then one coupon against a order id.
coupon_codes = list()
for redemption in coupon_redemption:
coupon_codes.append(redemption.coupon.code)
coupon_code_dict = {'coupon_code': ", ".join(coupon_codes)}
else:
coupon_code_dict = {'coupon_code': coupon_redemption.coupon.code}
coupon_code_dict = {'coupon_code': 'None'}
student_dict.update(dict(order_dict.items() + order_item_dict.items() + coupon_code_dict.items()))
student_dict.update({'course_id': course_id.to_deprecated_string()})
......
......@@ -32,11 +32,7 @@ class CouponDoesNotExistException(InvalidCartItem):
pass
class CouponAlreadyExistException(InvalidCartItem):
pass
class ItemDoesNotExistAgainstCouponException(InvalidCartItem):
class MultipleCouponsNotAllowedException(InvalidCartItem):
pass
......
......@@ -32,8 +32,7 @@ from verify_student.models import SoftwareSecurePhotoVerification
from .exceptions import (InvalidCartItem, PurchasedCallbackException, ItemAlreadyInCartException,
AlreadyEnrolledInCourseException, CourseDoesNotExistException,
CouponAlreadyExistException, ItemDoesNotExistAgainstCouponException,
RegCodeAlreadyExistException, ItemDoesNotExistAgainstRegCodeException)
MultipleCouponsNotAllowedException, RegCodeAlreadyExistException, ItemDoesNotExistAgainstRegCodeException)
from microsite_configuration import microsite
......@@ -498,31 +497,33 @@ class CouponRedemption(models.Model):
return value - discount
@classmethod
def add_coupon_redemption(cls, coupon, order):
def add_coupon_redemption(cls, coupon, order, cart_items):
"""
add coupon info into coupon_redemption model
"""
cart_items = order.orderitem_set.all().select_subclasses()
is_redemption_applied = False
coupon_redemptions = cls.objects.filter(order=order, user=order.user)
for coupon_redemption in coupon_redemptions:
if coupon_redemption.coupon.code != coupon.code or coupon_redemption.coupon.id == coupon.id:
log.exception("Coupon redemption already exist for user '{0}' against order id '{1}'"
.format(order.user.username, order.id))
raise MultipleCouponsNotAllowedException
for item in cart_items:
if getattr(item, 'course_id'):
if item.course_id == coupon.course_id:
coupon_redemption, created = cls.objects.get_or_create(order=order, user=order.user, coupon=coupon)
if not created:
log.exception("Coupon '{0}' already exist for user '{1}' against order id '{2}'"
.format(coupon.code, order.user.username, order.id))
raise CouponAlreadyExistException
coupon_redemption = cls(order=order, user=order.user, coupon=coupon)
coupon_redemption.save()
discount_price = cls.get_discount_price(coupon.percentage_discount, item.unit_cost)
item.list_price = item.unit_cost
item.unit_cost = discount_price
item.save()
log.info("Discount generated for user {0} against order id '{1}' "
.format(order.user.username, order.id))
return coupon_redemption
is_redemption_applied = True
return is_redemption_applied
log.warning("Course item does not exist for coupon '{0}'".format(coupon.code))
raise ItemDoesNotExistAgainstCouponException
return is_redemption_applied
class PaidCourseRegistration(OrderItem):
......
......@@ -77,18 +77,18 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
self.cart = Order.get_cart_for_user(self.user)
self.addCleanup(patcher.stop)
def get_discount(self):
def get_discount(self, cost):
"""
This method simple return the discounted amount
"""
val = Decimal("{0:.2f}".format(Decimal(self.percentage_discount / 100.00) * self.cost))
return self.cost - val
val = Decimal("{0:.2f}".format(Decimal(self.percentage_discount / 100.00) * cost))
return cost - val
def add_coupon(self, course_key, is_active):
def add_coupon(self, course_key, is_active, code):
"""
add dummy coupon into models
"""
coupon = Coupon(code=self.coupon_code, description='testing code', course_id=course_key,
coupon = Coupon(code=code, description='testing code', course_id=course_key,
percentage_discount=self.percentage_discount, created_by=self.user, is_active=is_active)
coupon.save()
......@@ -99,12 +99,12 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
course_reg_code = CourseRegistrationCode(code=self.reg_code, course_id=course_key, created_by=self.user)
course_reg_code.save()
def add_course_to_user_cart(self):
def add_course_to_user_cart(self, course_key):
"""
adding course to user cart
"""
self.login_user()
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
reg_item = PaidCourseRegistration.add_to_order(self.cart, course_key)
return reg_item
def login_user(self):
......@@ -122,8 +122,8 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
self.assertIn('The course {0} is already in your cart.'.format(self.course_key.to_deprecated_string()), resp.content)
def test_course_discount_invalid_coupon(self):
self.add_coupon(self.course_key, True)
self.add_course_to_user_cart()
self.add_coupon(self.course_key, True, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
non_existing_code = "non_existing_code"
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': non_existing_code})
self.assertEqual(resp.status_code, 404)
......@@ -131,23 +131,23 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
def test_course_discount_invalid_reg_code(self):
self.add_reg_code(self.course_key)
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
non_existing_code = "non_existing_code"
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': non_existing_code})
self.assertEqual(resp.status_code, 404)
self.assertIn("Discount does not exist against code '{0}'.".format(non_existing_code), resp.content)
def test_course_discount_inactive_coupon(self):
self.add_coupon(self.course_key, False)
self.add_course_to_user_cart()
self.add_coupon(self.course_key, False, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 404)
self.assertIn("Discount does not exist against code '{0}'.".format(self.coupon_code), resp.content)
def test_course_does_not_exist_in_cart_against_valid_coupon(self):
course_key = self.course_key.to_deprecated_string() + 'testing'
self.add_coupon(course_key, True)
self.add_course_to_user_cart()
self.add_coupon(course_key, True, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 404)
......@@ -156,7 +156,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
def test_course_does_not_exist_in_cart_against_valid_reg_code(self):
course_key = self.course_key.to_deprecated_string() + 'testing'
self.add_reg_code(course_key)
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
self.assertEqual(resp.status_code, 404)
......@@ -164,26 +164,64 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
def test_course_discount_for_valid_active_coupon_code(self):
self.add_coupon(self.course_key, True)
self.add_course_to_user_cart()
self.add_coupon(self.course_key, True, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
# unit price should be updated for that course
item = self.cart.orderitem_set.all().select_subclasses()[0]
self.assertEquals(item.unit_cost, self.get_discount())
self.assertEquals(item.unit_cost, self.get_discount(self.cost))
# after getting 10 percent discount
self.assertEqual(self.cart.total_cost, self.get_discount())
self.assertEqual(self.cart.total_cost, self.get_discount(self.cost))
# now using the same coupon code against the same order.
# Only one coupon redemption should be allowed per order.
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 400)
self.assertIn("Only one coupon redemption is allowed against an order", resp.content)
def test_course_discount_against_two_distinct_coupon_codes(self):
self.add_coupon(self.course_key, True, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
# now testing coupon code already used scenario, reusing the same coupon code
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
# unit price should be updated for that course
item = self.cart.orderitem_set.all().select_subclasses()[0]
self.assertEquals(item.unit_cost, self.get_discount(self.cost))
# now using another valid active coupon code.
# Only one coupon redemption should be allowed per order.
self.add_coupon(self.course_key, True, 'abxyz')
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': 'abxyz'})
self.assertEqual(resp.status_code, 400)
self.assertIn("Coupon '{0}' already used.".format(self.coupon_code), resp.content)
self.assertIn("Only one coupon redemption is allowed against an order", resp.content)
def test_same_coupons_code_on_multiple_courses(self):
# add two same coupon codes on two different courses
self.add_coupon(self.course_key, True, self.coupon_code)
self.add_coupon(self.testing_course.id, True, self.coupon_code)
self.add_course_to_user_cart(self.course_key)
self.add_course_to_user_cart(self.testing_course.id)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
# unit price should be updated for that course
item = self.cart.orderitem_set.all().select_subclasses()[0]
self.assertEquals(item.unit_cost, self.get_discount(self.cost))
item = self.cart.orderitem_set.all().select_subclasses()[1]
self.assertEquals(item.unit_cost, self.get_discount(self.testing_cost))
def test_soft_delete_coupon(self): # pylint: disable=E1101
self.add_coupon(self.course_key, True)
self.add_coupon(self.course_key, True, self.coupon_code)
coupon = Coupon(code='TestCode', description='testing', course_id=self.course_key,
percentage_discount=12, created_by=self.user, is_active=True)
coupon.save()
......@@ -218,7 +256,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
def test_course_free_discount_for_valid_active_reg_code(self):
self.add_reg_code(self.course_key)
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
self.assertEqual(resp.status_code, 200)
......@@ -236,7 +274,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.debug')
def test_non_existing_coupon_redemption_on_removing_item(self, debug_log):
reg_item = self.add_course_to_user_cart()
reg_item = self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]),
{'id': reg_item.id})
debug_log.assert_called_with(
......@@ -248,8 +286,8 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_existing_coupon_redemption_on_removing_item(self, info_log):
self.add_coupon(self.course_key, True)
reg_item = self.add_course_to_user_cart()
self.add_coupon(self.course_key, True, self.coupon_code)
reg_item = self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
......@@ -266,7 +304,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
def test_existing_reg_code_redemption_on_removing_item(self, info_log):
self.add_reg_code(self.course_key)
reg_item = self.add_course_to_user_cart()
reg_item = self.add_course_to_user_cart(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
self.assertEqual(resp.status_code, 200)
......@@ -282,8 +320,8 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_coupon_discount_for_multiple_courses_in_cart(self, info_log):
reg_item = self.add_course_to_user_cart()
self.add_coupon(self.course_key, True)
reg_item = self.add_course_to_user_cart(self.course_key)
self.add_coupon(self.course_key, True, self.coupon_code)
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
self.assertEquals(self.cart.orderitem_set.count(), 2)
......@@ -294,7 +332,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
items = self.cart.orderitem_set.all().select_subclasses()
for item in items:
if item.id == reg_item.id:
self.assertEquals(item.unit_cost, self.get_discount())
self.assertEquals(item.unit_cost, self.get_discount(self.cost))
elif item.id == cert_item.id:
self.assertEquals(item.list_price, None)
......@@ -310,7 +348,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_reg_code_free_discount_with_multiple_courses_in_cart(self, info_log):
reg_item = self.add_course_to_user_cart()
reg_item = self.add_course_to_user_cart(self.course_key)
self.add_reg_code(self.course_key)
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
self.assertEquals(self.cart.orderitem_set.count(), 2)
......@@ -338,7 +376,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_delete_certificate_item(self, info_log):
reg_item = self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
self.assertEquals(self.cart.orderitem_set.count(), 2)
......@@ -354,11 +392,11 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_remove_coupon_redemption_on_clear_cart(self, info_log):
reg_item = self.add_course_to_user_cart()
reg_item = self.add_course_to_user_cart(self.course_key)
CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
self.assertEquals(self.cart.orderitem_set.count(), 2)
self.add_coupon(self.course_key, True)
self.add_coupon(self.course_key, True, self.coupon_code)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
......@@ -372,7 +410,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.log.info')
def test_remove_registration_code_redemption_on_clear_cart(self, info_log):
reg_item = self.add_course_to_user_cart()
reg_item = self.add_course_to_user_cart(self.course_key)
CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
self.assertEquals(self.cart.orderitem_set.count(), 2)
......@@ -504,9 +542,9 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
self.assertEqual(resp2.status_code, 404)
def test_total_amount_of_purchased_course(self):
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
self.assertEquals(self.cart.orderitem_set.count(), 1)
self.add_coupon(self.course_key, True)
self.add_coupon(self.course_key, True, self.coupon_code)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
......@@ -526,8 +564,8 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.render_to_response', render_mock)
def test_show_receipt_success_with_valid_coupon_code(self):
self.add_course_to_user_cart()
self.add_coupon(self.course_key, True)
self.add_course_to_user_cart(self.course_key)
self.add_coupon(self.course_key, True, self.coupon_code)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.coupon_code})
self.assertEqual(resp.status_code, 200)
......@@ -536,14 +574,14 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
resp = self.client.get(reverse('shoppingcart.views.show_receipt', args=[self.cart.id]))
self.assertEqual(resp.status_code, 200)
self.assertIn('FirstNameTesting123', resp.content)
self.assertIn(str(self.get_discount()), resp.content)
self.assertIn(str(self.get_discount(self.cost)), resp.content)
@patch('shoppingcart.views.render_to_response', render_mock)
def test_reg_code_and_course_registration_scenario(self):
self.add_reg_code(self.course_key)
# One courses in user shopping cart
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
self.assertEquals(self.cart.orderitem_set.count(), 1)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
......@@ -585,7 +623,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
@patch('shoppingcart.views.render_to_response', render_mock)
def test_show_receipt_success_with_valid_reg_code(self):
self.add_course_to_user_cart()
self.add_course_to_user_cart(self.course_key)
self.add_reg_code(self.course_key)
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
......
......@@ -15,7 +15,8 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
from shoppingcart.reports import RefundReport, ItemizedPurchaseReport, UniversityRevenueShareReport, CertificateStatusReport
from student.models import CourseEnrollment
from .exceptions import ItemAlreadyInCartException, AlreadyEnrolledInCourseException, CourseDoesNotExistException, ReportTypeDoesNotExistException, \
CouponAlreadyExistException, ItemDoesNotExistAgainstCouponException, RegCodeAlreadyExistException, ItemDoesNotExistAgainstRegCodeException
RegCodeAlreadyExistException, ItemDoesNotExistAgainstRegCodeException,\
MultipleCouponsNotAllowedException
from .models import Order, PaidCourseRegistration, OrderItem, Coupon, CouponRedemption, CourseRegistrationCode, RegistrationCodeRedemption
from .processors import process_postpay_callback, render_purchase_form_html
import json
......@@ -154,9 +155,8 @@ def use_code(request):
Valid Code can be either coupon or registration code.
"""
code = request.POST["code"]
try:
coupon = Coupon.objects.get(code=code, is_active=True)
except Coupon.DoesNotExist:
coupons = Coupon.objects.filter(code=code, is_active=True)
if not coupons:
# If not coupon code then we check that code against course registration code
try:
course_reg = CourseRegistrationCode.objects.get(code=code)
......@@ -165,7 +165,7 @@ def use_code(request):
return use_registration_code(course_reg, request.user)
return use_coupon_code(coupon, request.user)
return use_coupon_code(coupons, request.user)
def use_registration_code(course_reg, user):
......@@ -183,17 +183,23 @@ def use_registration_code(course_reg, user):
return HttpResponse(json.dumps({'response': 'success'}), content_type="application/json")
def use_coupon_code(coupon, user):
def use_coupon_code(coupons, user):
"""
This method utilize course coupon code
"""
try:
cart = Order.get_cart_for_user(user)
CouponRedemption.add_coupon_redemption(coupon, cart)
except CouponAlreadyExistException:
return HttpResponseBadRequest(_("Coupon '{0}' already used.".format(coupon.code)))
except ItemDoesNotExistAgainstCouponException:
return HttpResponseNotFound(_("Coupon '{0}' is not valid for any course in the shopping cart.".format(coupon.code)))
cart = Order.get_cart_for_user(user)
cart_items = cart.orderitem_set.all().select_subclasses()
is_redemption_applied = False
for coupon in coupons:
try:
if CouponRedemption.add_coupon_redemption(coupon, cart, cart_items):
is_redemption_applied = True
except MultipleCouponsNotAllowedException:
return HttpResponseBadRequest(_("Only one coupon redemption is allowed against an order"))
if not is_redemption_applied:
log.warning("Course item does not exist for coupon '{0}'".format(coupons[0].code))
return HttpResponseNotFound(_("Coupon '{0}' is not valid for any course in the shopping cart.".format(coupons[0].code)))
return HttpResponse(json.dumps({'response': 'success'}), content_type="application/json")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment