Doing something when payment is successfull with stripe and DjangoRest - django

I integrated stripe payment in my projects so now i can make a payment.
My app about an advertising app so the ad keep active for 30 days then disappear so i want to use payment to extend the expiration date of the ad.
Here is Payment view:
class StripeCheckoutView(APIView):
def post(self, request):
try:
checkout_session = stripe.checkout.Session.create(
line_items=[
{
'price': 'price_1MPUIXGslCuRnIIuUV1ME6Kn',
'quantity': 1,
},
],
payment_method_types=['card',],
mode='payment',
success_url=settings.SITE_URL + '/?success=true&session_id={CHECKOUT_SESSION_ID}',
cancel_url=settings.SITE_URL + '/?canceled=true',
)
return redirect(checkout_session.url)
except:
return Response(
{'error': 'Something went wrong when creating stripe checkout session'},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
models:
class Advertise(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="advertise")
category = models.CharField(max_length= 200, choices = CATEGORY)
location = models.CharField(max_length= 200, choices = LOCATIONS)
description = models.TextField(max_length=600)
price = models.FloatField(max_length=100)
expiration_date = models.DateField(default = Expire_date, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
EDIT :
I want to use payment to extend the duration of the expiration date.
So when the user made the payment the expiration date be 60 days.

Related

When to make stripe subscription object and assign to user - Django

Tech Stack - Django, Angular
I have been implementing stripe subscription model but stuck at some absurd scenario. I am getting Subscription not found by django. Please read the full scenario.
Firstly I am successfull in creating stripe session.
Code
session = stripe.checkout.Session.create(
metadata={'price_id':request.data.get('price_id'),'product_id':request.data.get('product_id'),'product_name':request.data.get('product_name')},
client_reference_id=request.user.id,
customer=customer.stripe_customer_id,
success_url='http://localhost:4200/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='http://localhost:4200/canceled.html',
mode='subscription',
line_items=[{
'price': request.data['price_id'],
# For metered billing, do not pass quantity
'quantity': 1,
}],
)
Webhooks Implementation:
checkout.session.completed
I am creating customer and subscription model in my db.
print(user)
customer = RecruiterUserProfile.objects.get(user = user)
print(customer)
customer.customer_id = session.customer
customer.save()
stripecustomer = Customer.objects.get(recruiter = customer, checkout_session_id = stripe_session_id)
print(stripecustomer)
stripecustomer.stripe_customer_id = stripe_customer_id
stripecustomer.save()
subscription,created = Subscriptions.objects.get_or_create(recruiter = customer,
sub_id=stripe_subscription_id,customer_id = stripecustomer,stripe_customer_id = stripe_customer_id,
payment_status=stripe_payment_status, amount = stripe_amount,
status = stripe_status, product_id = stripe_metadata['product_id'], price_id = stripe_metadata['price_id'], product_name = stripe_metadata['product_name'])
invoice.paid
Then it triggers Invoice.paid, in which I am getting the subscription model and update others values in it. But since webhooks do not wait for our calls, Sometimes, It doesn't find the subscription.
Now if I create subscription and customer in invoice.paid webhook using ger_or_create, How am I supposed to link it to the user.
Below are my models:
class Customer(models.Model):
recruiter = models.OneToOneField(RecruiterUserProfile, on_delete=models.PROTECT)
stripe_customer_id = models.CharField(max_length=80, blank=True, null=True)
checkout_session_id = models.CharField(max_length=100,blank=True,null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.recruiter.user.email} has a stripe customer id {self.stripe_customer_id}"
def expiration():
return now() + timedelta(days=30)
class Subscriptions(models.Model):
STATUS_CHOICES =(
('utilised','Utilised'),
('accessible','Accessible'),
('notaccessible','Notaccessible')
)
recruiter = models.ForeignKey(RecruiterUserProfile, on_delete=models.PROTECT)
customer_id = models.ForeignKey(Customer, on_delete=models.PROTECT)
stripe_customer_id = models.CharField(max_length=80, blank=True, null=True)
sub_id = models.CharField(max_length=80, blank=True, null=True)
product_id = models.CharField(max_length=80, blank=True, null=True)
product_name = models.CharField(max_length=80, null=True, blank=True)
price_id = models.CharField(max_length=80, blank=True, null=True)
offer_id = models.CharField(max_length=80, blank=True, null=True)
notes = models.JSONField(default=list,blank=True)
status = models.CharField(max_length=100, default="Initial")
payment_status = models.CharField(max_length = 100, default='')
amount = models.CharField(max_length=20,blank=True, null=True)
start_date = models.DateTimeField(null=True, blank=True)
expiration_date = models.DateTimeField(
default=expiration,
verbose_name='Expirate in'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
client_validity = models.CharField(max_length=20,choices= STATUS_CHOICES, default='accessible')
product_job_credits = models.IntegerField(default=0)
active_job_credits = models.IntegerField(default=0)
is_cancelled = models.BooleanField(default=False)
I managed to solve this question by just simple workflow change. Do not call the subscription API directly. Create a stripe customer initially by yourself and store the value in your local db. So while creation subscription, you will be able to get the customer and It will be easy to link the subscription with the customer.
I can share the code if necessary.

Why do I always get a message that there are insufficient money, even though the amount I'm withdrawing is less than my balance?

I intended to show the user the message "insufficient balance" when the amount he wants to withdraw is larger than the available balance, but the message appears even when the amount he wants to withdraw is less. What's the problem here, exactly?
Views
def create_withdrawal_view(request):
if request.method == 'POST':
withdraw_form = WithdrawalForm(request.POST)
if withdraw_form.is_valid():
investment = withdraw_form.save(commit=False)
if investment.balance < investment.amount:
messages.success(request, 'insufficient funds')
else:
investment.balance -= investment.withdraw_amount
investment.save()
messages.success(request, 'investment successful')
else:
withdraw_form = WithdrawalForm()
context = {'withdraw_form': withdraw_form}
return render(request, 'create-withdrawal.html', context)
My Model
class Investment(models.Model):
PLAN_CHOICES = (
("Basic - Daily 2% for 180 Days", "Basic - Daily 2% for 180 Days"),
("Premium - Daily 4% for 360 Days", "Premium - Daily 4% for 360 Days"),
)
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, blank=True)
plan = models.CharField(max_length=100, choices=PLAN_CHOICES, null=True)
deposit_amount = models.IntegerField(default=0, null=True)
basic_interest = models.IntegerField(default=0, null=True)
premium_interest = models.IntegerField(default=0, null=True)
investment_return = models.IntegerField(default=0, null=True)
withdraw_amount = models.IntegerField(default=0, null=True, blank=True)
balance = models.IntegerField(default=0, null=True, blank=True)
locked_balance = models.IntegerField(default=0, null=True, blank=True)
investment_id = models.CharField(max_length=10, null=True, blank=True)
is_active = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now=True, null=True)
due_date = models.DateTimeField(null=True)
My Model Forms
class InvestmentForm(forms.ModelForm):
class Meta:
model = Investment
fields = ['deposit_amount', 'plan']
class WithdrawalForm(forms.ModelForm):
class Meta:
model = Investment
fields = ['withdraw_amount']
My urls.py
urlpatterns = [
path('dashboard/', views.list_investments, name='list-investments'),
path('create/', views.create_investment_view, name='create-investment'),
path('withdraw/', views.create_withdrawal_view, name='withdraw'),
]
Believe you are using the wrong data here:
def create_withdrawal_view(request):
if request.method == 'POST':
withdraw_form = WithdrawalForm(request.POST)
if withdraw_form.is_valid():
investment = withdraw_form.save(commit=False)
if investment.balance < withdraw_form.withdraw_amount:
messages.success(request, 'insufficient funds')
else:
investment.balance -= withdraw_amount.withdraw_amount
investment.save()
messages.success(request, 'investment successful')
else:
withdraw_form = WithdrawalForm()
context = {'withdraw_form': withdraw_form}
return render(request, 'create-withdrawal.html', context)
You have to validate the data of your form withdraw_form.withdraw_amount. not instance.amount.
But also you have in some way to get the investment from where you need to withdraw I believe you need to get the pk and do something like this:
investment = Investment.objects.get(pk=pk)

Django User matching query does not exist on foreign-key relation

I am trying to create a system in Django by which users will login using a phone number. Used AbstractBaseUser to use the number as user id. Now I am trying to create a foreign key relation of every transaction with the number. While I try to push a transaction, it says "User matching query does not exist". I am getting where I made mistake.
User model:
class User(AbstractBaseUser, PermissionsMixin):
phone_number = models.CharField("Phone number", max_length=100, unique=True, error_messages={
'unique': ("number_existsssss"),
})
name = models.TextField("Name")
time_stamp = models.DateTimeField("Time-Date", auto_now=True)
request_type = models.CharField(max_length=100, default="check"
is_staff = models.BooleanField(verbose_name=('staff status'), default=False)
is_active = models.BooleanField(verbose_name=('active'), default=True)
Transaction Model:
class TransactionModel(models.Model):
trxID = models.CharField(max_length=15, null=True, unique=True)
User = models.ForeignKey(to=User, to_field="phone_number", related_name='transaction', on_delete=models.DO_NOTHING, default=1)
time = models.DateTimeField(auto_now=True, null=True)
amount = models.CharField(max_length=5, null=True)
pay_method = models.CharField(max_length=10, null=True)
amountReceivedFrom = models.CharField(max_length=26, null=True)
transactionStatus = models.CharField(max_length=15, null=True, default='False')
view for add-cash/b-kash request:
class BkashCashinView(APIView):
#transaction.atomic
def post(self, request, *args, **kwargs):
HEADERS = {
"Access-Control-Allow-Origin": "*"
}
if request.method == 'POST':
serializer = BkashCashinSerializer(data = request.data)
# serializer.is_valid()
req = request.data
trx_id = req.get('trxID')
print(trx_id)
phone_number = req.get('phone_number')
recharge_amount = float(req.get('amount'))
number_exists = User.objects.filter(phone_number=phone_number).exists()
user = User.objects.get(phone_number=phone_number)
print(user)
current_user_data = User.objects.select_for_update().get(phone_number=phone_number)
# current_user_data = User.objects.get(phone_number=phone_number)
with transaction.atomic():
current_user_data.current_balance += recharge_amount
current_user_data.save()
print("phone numbe", req.get("amount"))
serializer.is_valid(raise_exception=True)
current_balance = current_user_data.current_balance
context = {
"current_balance": current_balance,
"status": "success"
}
serializer.save()
# print(trx_id)
return Response(context, headers = HEADERS)
I think I made some mistakes with the foreign key relation. The error shows:
raise self.model.DoesNotExist(
user_signup.models.User.DoesNotExist: User matching query does not exist.
[04/Sep/2021 18:44:22] "POST /add-cash/b-kash HTTP/1.1" 500 20728

Django querying models with foreignkey

I am creating a project of customer management, in this I want to query some models which are related with foreign key.
I have created these models.
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=250, null=True)
phone = models.CharField(max_length=10, null=True)
email = models.CharField(max_length=250, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
# to get name as string on behalf of "Customer Object 1" in DB.
def __str__(self):
return self.name
class Tag(models.Model):
name = models.CharField(max_length=250, null=True)
def __str__(self):
return self.name
class Product(models.Model):
# To make a dropdown menu to choose category.
CATEGORY = (
('Indoor', 'Indoor'),
('Out Door', 'Out Door'),
)
name = models.CharField(max_length=250, null=True)
price = models.FloatField(null=True)
category = models.CharField(max_length=250, null=True, choices=CATEGORY)
description = models.CharField(max_length=250, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Order(models.Model):
# To make a dropdown menu to choose status.
STATUS = (
('Pending', 'Pending'),
('Out for Delivery', 'Out for Delivery'),
('Delivered', 'Delivered'),
)
customer = models.ForeignKey(Customer, null=True,
on_delete=models.SET_NULL)
product = models.ForeignKey(Product, null=True,
on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=250, null=True, choices=STATUS)
Views.py
from django.shortcuts import render
from .models import *
def home(request):
customers = Customer.objects.all()
orders = Order.objects.all()
total_customers = customers.count()
total_orders = orders.count()
delivered = orders.filter(status='Delivered').count()
pending = orders.filter(status='Pending').count()
front_end_stuff = {'customers': customers, 'orders': orders,
'total_customers': total_customers, 'total_orders': total_orders,
'delivered': delivered, 'pending': pending,
}
return render(request, 'accounts/dashboard.html', context=front_end_stuff)
def products(request):
products_ = Product.objects.all()
return render(request, 'accounts/products.html', context={'products': products_})
def customer(request, pk):
customers = Customer.objects.filter(id=pk)
orders = Order.objects.filter(id=pk)
customer_products = Product.objects.filter(id=pk)
total_orders = orders.count()
front_end_stuff = {'customers': customers, 'orders': orders,
'total_orders': total_orders, 'customer_products': customer_products
}
return render(request, 'accounts/customer.html', context=front_end_stuff)
I want to get status of the orders placed by a specific customer, also i have set the dynamic urls for getting customer profile view page and in it i want to loop through it and print out the status in respective field.
I have attached the image of customer profile view page where i want the data.
customer_profile_view_page
I tried one query which i found on internet is :
customers = Customer.objects.filter(id=pk)
status = customers.order_set.all()
but I get an error
AttributeError: 'QuerySet' object has no attribute 'order_set'
I am using :
Windows 10,
Python 3.7,
Django 3.0.7.
To get the list of all the orders of a customer, you can try -
# this will give the list of orders for customer with id = pk
orders = Order.objects.filter(customer__id=pk) # it's a double underscore
You can iterate each order to fetch the status -
for order in orders:
print(order.status)
Or with what you tried, use .get instead of .filter.
customer = Customer.objects.get(id=pk) # the customer has to be present with this id else it will give an exception.
orders = customer.order_set.all()
Doc

How to Fetch Data in ManyToMany Django And render in view.py

I want to fetch Data to my view.py where the buyer select a specific market. Which Means the Buyer can only see the Market he selects.
class Market(models.Model):
name = models.CharField(max_length=30)
address = models.TextField("Market Address")
interval = models.PositiveIntegerField("Market Day Interval", default=5)
startdate = models.DateField("Initial Date", auto_now=False, auto_now_add=False)
location = models.ForeignKey(Local, related_name='market_location', on_delete=models.CASCADE)
desciption = models.TextField("Good Description")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Buyer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
market = models.ManyToManyField(Market, related_name='interested_markets')
status = models.BooleanField("User Status", default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
view.py
#login_required
#buyer_required
def welcome_buyer(request):
buyer = request.user.buyer
market = buyer.interested_markets.all()
return render(request, 'buyer/home.html', {
'market': market
})
you can simply iterate over this using your buyer object:
for market in buyer.market_set.all()
or
markets = buyer.market_set.all()
in your case it would be:
markets = buyer.interested_markets_set.all()
or
markets = buyer.market # you should consider changing it's name to be plural to indicate that it's a list of objects like: buyer.markets
for more details read the docs here: django many to many