I am sending cart data from the cookies to Stripe and retrieving it, but I am unable to find a solution to process it correctly.
Please help!
I am learning Django and wanted to save the cart items of non-logged users into the cookies and send it to Stripe, as Metadata.
From there retrieve it and if the checkout is completed to process the order, but I am unsuccessful to process the data that is retrieved to be able to save the order.
Stripe Checkout Session:
#csrf_exempt
def create_checkout_session(request):
stripe.api_key = settings.STRIPE_SECRET_KEY
domain_url = 'http://localhost:8000/checkout/'
if request.user.is_authenticated:
customer = request.user.customer
else:
data = json.loads(request.body)
total = data['form']['total'].replace('.', '')
email = data['form']['email']
first_name = data['form']['first_name']
last_name = data['form']['last_name']
customer, created = Customer.objects.get_or_create(
email=email
)
customer.first_name = first_name
customer.last_name = last_name
customer.save()
cart_info = cart_details(request)
cart_items = cart_info['cart_items']
order = cart_info['order']
items = cart_info['items']
print(items)
if request.method == 'GET':
checkout_session = stripe.checkout.Session.create(
shipping_address_collection={
"allowed_countries":
["US", "CA", "NL", "GB"]
},
client_reference_id=request.user.id,
customer_email=request.user.email,
success_url=domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
cancel_url=domain_url + 'cancelled/',
payment_method_types=['card'],
mode='payment',
line_items=[
{
'name': 'Kenpachi Katana Store',
'quantity': 1,
'currency': 'usd',
'amount': int(order.get_cart_total*100),
}
]
)
return JsonResponse({'sessionId': checkout_session['id']})
else:
checkout_session = stripe.checkout.Session.create(
shipping_address_collection={
"allowed_countries":
["US", "CA", "NL"]
},
**metadata=[items]**,
client_reference_id=customer.id,
customer_email=email,
success_url=domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
cancel_url=domain_url + 'cancelled/',
payment_method_types=['card'],
mode='payment',
line_items=[
{
'name': 'Kenpachi Katana Store',
'quantity': 1,
'currency': 'usd',
'amount': total,
}
]
)
return JsonResponse({'sessionId': checkout_session['id']})
Terminal Output with the Cookie Cart variable:
print(type(items))
<class 'list'>
And:
[{'product':
`{'id': 1,
'name': 'Sasuke Katana',
'price': Decimal('270.00'),
'imageURL': '/media/1_ccbb983f-a35d-40f8-8efb-dc55db02ad8f_700x.webp'},
'quantity': 1,
'get_total': Decimal('270.00')},
`
{'product':
{'id': 3,
'name': 'Zoro Katana',
'price': Decimal('260.00'),
'imageURL': '/media/1_466b0afb-d483-4a32-b0bb-89388aeccaa4_700x.webp'},
'quantity': 1,
'get_total': Decimal('260.00')
}]
And it easy to loop through it
for item in items:
print(item)
Output:
enter image description here
After the the order is completed, I retrieve the Stripe Session to fulfill the order
#csrf_exempt
def stripe_webhook(request):
stripe.api_key = settings.STRIPE_SECRET_KEY
endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
try:
event = stripe.Webhook.construct_event(
payload,
sig_header,
endpoint_secret
)
except ValueError as e:
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
return HttpResponse(status=400)
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
session = stripe.checkout.Session.retrieve(
event['data']['object']['id'],
expand=['line_items'],
)
stripe_metadata = session['metadata'].setdefault('0')
print(stripe_metadata)
print(type(stripe_metadata))
# Fulfill the purchase...
# TODO: drill down on the metadata from stripe
transaction_id = datetime.datetime.now().timestamp()
total = session['amount_total']
customer_id = session['client_reference_id']
customer = Customer.objects.get(pk=customer_id)
order, created = Order.objects.get_or_create(
customer=customer,
complete=False
)
order.transaction_id = transaction_id
if (total / 100) == int(order.get_cart_total):
order.complete = True
ShippingAddress.objects.create(
customer=customer,
order=order,
address=session['shipping']['address']['line1'],
city=session['shipping']['address']['city'],
state=session['shipping']['address']['state'],
zipcode=session['shipping']['address']['postal_code'],
country=session['shipping']['address']['country'],
)
order.save()
print('Order was added to the database')
return HttpResponse(status=200)
Terminal Output:
enter image description here
What would be the best option to retrieve it in the same format, to be able to iterate through the products of the cart.
Any help would be deeply appreciated.
GitHub repo with the cookie cart function:
https://github.com/GeorgianF/Kenpachi-P5-CI/blob/main/cart/utils.py
Thank you!
Maybe you can try
stripe_metadata = json.loads(str(stripe_metadata))
to convert string to JSON format
Related
first time I ask on the website.
I was testing a Django Restframework app.
The is to check an unauthenticated user that wants to create a review.
I got this error:
TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x7f5e95756920>.
this is the class test:
class ReviewTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username="example", password="Password#123")
self.token = Token.objects.get(user__username=self.user)
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
self.stream = models.StreamPlatform.objects.create(
name="Netflix",
about="#1 Platform",
website="https://www.netflix.com"
)
self.watchlist = models.WatchList.objects.create(
platform=self.stream, title="Example Movie",
storyline="Example Movie",
active=True
)
self.watchlist2 = models.WatchList.objects.create(platform=self.stream, title="Example Movie",
storyline="Example Movie", active=True)
self.review = models.Review.objects.create(review_user=self.user, rating=5, description="Great Movie",
watchlist=self.watchlist2, active=True)
def test_review_create(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(models.Review.objects.count(), 2)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
**#The test who cause the error**
def test_review_create_unauth(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
self.client.force_authenticate(user=None, token=None)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_review_update(self):
data = {
"review_user": self.user,
"rating": 4,
"description": "Great Movie! - Updated",
"watchlist": self.watchlist,
"active": False
}
response = self.client.put(
reverse('review-detail', args=(self.review.id,)), data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_list(self):
response = self.client.get(
reverse('movie-review', args=(self.watchlist.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind(self):
response = self.client.get(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind_delete(self):
response = self.client.delete(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
def test_review_user(self):
response = self.client.get(
'/watch/review/?username' + self.user.username)
self.assertEqual(response.status_code, status.HTTP_200_OK)
In data items, you are passing an object, and you have to pasa an id. Change this:
review_user: self.user.id
Thanks to everyone,
I found the mistake.
In fact the problem was not in the func in the tests.py but in the view,
where I misspelled:
permission_classes = [IsAuthenticated]
with:
permission_clasees = [IsAuthenticated]
So everything is fine now.
Thanks again to all of you
I am trying to send otp and then validate otp for login. I am able to send otp but it is not validating for some reason.
the code for sending otp is below and it is working fine-
class SendOTP(APIView):
permission_classes = (AllowAny, )
def post(self, request, *args, **kwargs):
email = request.data.get('email')
if email:
email = str(email)
user = User.objects.filter(email__iexact = email)
if user.exists():
key = send_otp(email)
if key:
old = User.objects.filter(email__iexact=email)
if old.exists():
old = old.first()
count = old.count
old.count = count + 1
old.save()
print('Count Increase', count)
return Response({
'status': True,
'detail': 'OTP sent successfully.'
})
code for generating 6 digit otp is -
def send_otp(email):
if email:
digits = [i for i in range(0, 10)]
key = ""
for i in range(6):
index = math.floor(random.random() * 10)
key += str(digits[index])
print(key)
return key
else:
return False
code for validating email and otp is below but it is not working-
class ValidateOTP(APIView):
permission_classes = (AllowAny, )
def post(self, request, *args, **kwargs):
email = request.data.get('email' , False)
otp_sent = request.data.get('otp', False)
if email and otp_sent:
e_mail = User.objects.filter(email__iexact = email)
if e_mail.exists():
e_mail = e_mail.first()
otp = e_mail.otp
print(otp, e_mail, otp_sent)
if str(otp_sent) == str(otp):
old.validated = True
old.save()
try:
payload = JWT_PAYLOAD_HANDLER(old)
jwt_token = JWT_ENCODE_HANDLER(payload)
update_last_login(None, old)
except User.DoesNotExist:
raise serializers.ValidationError(
'User with given email and password does not exists'
)
return Response({
'status' : True,
'email': email,
'token': jwt_token,
'detail' : 'OTP mactched.'
})
else:
return Response({
'status' : False,
'detail' : 'OTP incorrect.'
})
else:
return Response({
'status' : False,
'detail' : 'First proceed via sending otp request.'
})
else:
return Response({
'status' : False,
'detail' : 'Please provide both email and otp for validations'
})
it's is showing None for otp = e_mail.otp. is there a way to make it work?
I don't see where old.otp is being set in the SendOTP class, that's probably why it's None. Should be something like this:
old.count = count + 1
old.otp = key
old.save()
Also, if old.exists(): looks weird in ValidateOTP, since there is no references to the old variable, probably should be if e_mail.exists().
I've integrated Django with Stripe and seems that works ok. However i have a problem by showing all products in stripe checkout page. I need to tell stripe which products we're going to buy. If i have 2 products in cart i see only one product in stripe checkout.
views.py
def payments_stripe(request):
YOUR_DOMAIN = "http://127.0.0.1:8000/orders"
print(request.body)
body = json.loads(request.body)
cart = Cart.objects.get(cart_id=_cart_id(request))
cart_items = cartItem.objects.filter(cart=cart, is_active=True)
print(cart_items)
order = Order.objects.get(cart=cart, is_ordered=False, order_number=body['orderID'])
print(order)
for cart_item in cart_items:
quantity = cart_item.quantity
print(quantity)
name = cart_item.product.name
print(name)
try:
checkout_session = stripe.checkout.Session.create(
customer_email=order.email,
billing_address_collection='auto',
payment_method_types=['card'],
line_items=[
{
'price_data': {
'currency': 'eur',
'unit_amount': int(order.order_total * 100),
'product_data': {
'name': name,
'images': ['https://i.imgur.com/EHyR2nP.png'],
},
},
'quantity': quantity,
},
],
metadata={
'order_number': body['orderID'],
'payment_method': body['payment_method'],
'cart_id': cart,
},
mode='payment',
success_url=YOUR_DOMAIN + '/success/',
cancel_url=YOUR_DOMAIN + '/cancel/',
)
return JsonResponse({'id': checkout_session.id})
except Exception as e:
return JsonResponse(error=str(e)), 403
I iterate over cart items and Iteration gives:
1
Golden Arrow
1
Silver Heart
However in Stripe dashboard i see only one product 1 Golden Arrow.
I suppose i need to create a new list. Is that right? How can i do that in my case?
Thank you
You need to actually add each item to the line_items array, so you want to do something more like this:
line_items = []
for cart_item in cart_items:
# I presume you have something like cart_item.amount, right?
unit_amount = int(cart_item.amount * 100)
line_items.add({
'price_data': {
'currency': 'eur',
'unit_amount': unit_amount,
'product_data': {
'name': cart_item.product.name,
'images': ['https://i.imgur.com/EHyR2nP.png'],
},
},
'quantity': cart_item.quantity,
})
try:
checkout_session = stripe.checkout.Session.create(
customer_email=order.email,
billing_address_collection='auto',
payment_method_types=['card'],
line_items=line_items,
metadata={
'order_number': body['orderID'],
'payment_method': body['payment_method'],
'cart_id': cart,
},
mode='payment',
success_url=YOUR_DOMAIN + '/success/',
cancel_url=YOUR_DOMAIN + '/cancel/',
)
I have a working code which gets all incident details.
But i am unable to save complete data in database only the last record gets saved
def incidents(request):
incidentsServicenow = IncidentsServicenow()
c = pysnow.Client(instance='', user='', password='')
# Define a resource, here we'll use the incident table API
incident = c.resource(api_path='/table/incident')
print('incident', incident)
# Query for incidents with state 1
response = incident.get()
print('response', response)
# Iterate over the result and print out `sys_id` of the matching records.
ticket = []
for record in response.all():
data = {
'number': record['number'],
'description': record['description'],
'short_description': record['short_description'],
'state': record['state'],
}
#print(record['number'])
incidentsServicenow.number = data['number']
incidentsServicenow.title = data['short_description']
incidentsServicenow.description = data['description']
incidentsServicenow.state = data['state']
#ticket.append(data)
print("storing data")
incidentsServicenow.save()
return HttpResponse(ticket, content_type='application/json')
My model is
class IncidentsServicenow(models.Model):
number = models.CharField(max_length=32)
title = models.CharField(max_length=160)
description = models.TextField()
state = models.CharField(max_length=20)
class Meta:
managed = False
db_table = 'incidents_servicenow'
I need to save all the records in database
You should create objects in the loop. From the code, I can see that you created the incidentsServicenow object is created outside the loop.
for record in response.all():
data = {
'number': record['number'],
'description': record['description'],
'short_description': record['short_description'],
'state': record['state'],
}
#print(record['number'])
incidentsServicenow = IncidentsServicenow()
incidentsServicenow.number = data['number']
incidentsServicenow.title = data['short_description']
incidentsServicenow.description = data['description']
incidentsServicenow.state = data['state']
ticket.append(data)
print("storing data")
incidentsServicenow.save()
return HttpResponse(ticket, content_type='application/json')
or you could do like this
for record in response.all():
data = {
'number': record['number'],
'description': record['description'],
'short_description': record['short_description'],
'state': record['state'],
}
#print(record['number'])
incidentsServicenow = IncidentsServicenow(number=data['number'],
title=data['short_description'],description=data['description'],state=data['state'])
ticket.append(data)
print("storing data")
incidentsServicenow.save()
return HttpResponse(ticket, content_type='application/json')
Add below line inside for loop
incidentsServicenow = IncidentsServicenow()
I'm trying write a small app while I'm learning django.However, when I try to save the form data in database, some problems happen to me.I use python3.4 and django 1.8.4, my database is MySql
The first problem I met is that the database doesn't have any data
this is my model code:
SUBJECT_CHOICES = (
('computerscience', '计算机科学导论'),
('C-sharp', 'C#'),
('cplusplus', 'C++'),
('CCNA', 'CCNA'),
('ACM', 'ACM'),
('linux', 'linux'),
('java', 'java'),
('python', 'python')
)
class Homework(models.Model):
handin_date = models.DateTimeField('交作业时间')
subject = models.CharField(verbose_name = '课程', default = '计算机科学导论', max_length = 20, choices = SUBJECT_CHOICES)
code = models.TextField(verbose_name = '代码', default = '')
xuehao = models.CharField(verbose_name = '学号', default = '', max_length = 9)
name = models.CharField(verbose_name = '姓名', default = '', max_length = 10)
this is my view code:
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
form = HomeworkForm(initial = { 'xuehao': '学号', 'name': '姓名', 'subject': '计算机科学导论', 'handin_date': dt.now(), 'code': '你的代码' })
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
In this way there's nothing in my database
The seconde question is when I tried another way, I get a None value in my datebase
The same model code as before
Here is my view code:
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
homework = Homework.objects.create(xuehao = '学号', name = '姓名', subject = '计算机科学导论', handin_date = dt.now(), code = '你的代码')
form = HomeworkForm(instance = homework)
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
the '课程' means 'subject'
How can I deal with these problems?
I' really appriciate your help!
After all check if form.is_valid(), you need save the form.
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
form = HomeworkForm(initial = { 'xuehao': '学号', 'name': '姓名', 'subject': '计算机科学导论', 'handin_date': dt.now(), 'code': '你的代码' })
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
At the second way, you are creating a new HomeWork everytime a URL is accessed, without submit any post data.