When to make stripe subscription object and assign to user - Django - 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.

Related

get the related records in a serializer - django

I am trying to obtain in a query the data of a client and the contacts he has registered I tried to do it in the following way but it did not work.
class ClientReadOnlySerializer(serializers.ModelSerializer):
clientcontacts = ClientContactSerializer(many=True, read_only=True)
class Meta:
model = Client
fields = "__all__"
Is there any way to make this relationship nested?
these are my models
clients model
# Relations
from apps.misc.models import City, TypeIdentity, TypeCLient, CIIU
from apps.clients.api.models.broker.index import Broker
from apps.authentication.models import User
class Client(models.Model):
id = models.CharField(max_length=255, unique=True,primary_key=True, editable=False)
type_client = models.ForeignKey(TypeCLient, on_delete=models.CASCADE, blank=True)
type_identity = models.ForeignKey(TypeIdentity, on_delete=models.CASCADE, blank=True)
document_number = models.CharField(max_length=255, blank=True, unique=True)
first_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255, blank=True, null=True)
social_reason = models.CharField(max_length=255, blank=True, null=True)
city = models.ForeignKey(City, on_delete=models.CASCADE, blank=True)
address = models.CharField(max_length=255, blank=True)
email = models.CharField(max_length=255, blank=True, unique=True)
phone_number = models.CharField(max_length=255, blank=True, unique=True)
ciiu = models.ForeignKey(CIIU, on_delete=models.CASCADE, blank=True)
broker = models.ForeignKey(Broker, on_delete=models.CASCADE, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
income = models.SmallIntegerField(blank=True, default=0)
state = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(null=True, default=None)
client contacts model
# Relations
from apps.clients.api.models.index import Client
class ClientContact(models.Model):
id = models.CharField(max_length=255, primary_key=True, unique=True, editable=False)
client = models.ForeignKey(Client, on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
phone_number = models.CharField(max_length=255)
state = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(null=True, blank=True, default=None)
after some research I came up with a solution that doesn't seem very practical, what I did was to create a method in the serializer that queries the client's contacts as follows
class ClientReadOnlySerializer(serializers.ModelSerializer):
contacts = serializers.SerializerMethodField(method_name='get_contacts')
class Meta:
model = Client
fields = "__all__"
extra_fields = ['contacts']
def get_contacts(self, obj):
contacts = ClientContact.objects.filter(client=obj)
serializer = ClientContactSerializer(contacts, many=True)
return serializer.data
using the model and the serializer of the contact model I made a query which I added in an extra field of the customer serializer, if someone knows how to make this process more optimal please reply.

how to write a signal to change a field in a model after another filed from another model is changed

I have a user model that has to go through several tasks such as completing their information, taking some tests, and interviews. So I added a progress level field that shows the user status at the moment. this is my model:
class User(AbstractUser):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
isPreRegistered = models.BooleanField(default=False)
role = models.CharField(max_length=25, null=True, choices=USER_ROLE_CHOICES, default=USER_ROLE_CHOICES[0][0])
role_id = models.CharField(max_length=10, default='applicant')
username = models.CharField(unique=True, max_length=13)
first_name = models.CharField(max_length=32, null=True, default=None)
last_name = models.CharField(max_length=64, null=True, default=None)
gender = models.CharField(max_length=10, null=True)
personalInfo = models.OneToOneField(PersonalInfo, on_delete=models.CASCADE, null=True)
contactInfo = models.OneToOneField(ContactInfo, on_delete=models.Case, null=True)
eliteInfo = models.OneToOneField(EliteInfo, on_delete=models.CASCADE, null=True)
progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS, default=USER_PROGRESS_LEVELS[0][0])
and there are multiple models which are connected to the user model using a foreign key relation.
this is one of the models I added here for instance:
class PsychologicInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
final_assessment = models.TextField(null=True, blank=True)
is_approved = models.CharField(max_length=64, blank=True)
is_interviewed = models.BooleanField(default=False)
I want to write a signal or a save method that does something like this:
if the is_interviewed field was True, change that progress_level to USER_ROLE_CHOICES[1][0]
I have no idea how to do this so thanks for the tips
You can override the .save() method of PsychologicInfo
class PsychologicInfo:
...
def save(self):
super().save()
if self.is_interviewed:
self.user.role = USER_ROLE_CHOICES[1][0] # or enter value here
self.user.save()
or you can use Django signals.

how to make relationship in django model

models.py
So,here i want to make Invoicemgmt model in which i can have multiple entries for Invoice table having
customer,project and Invoice_amount.
Basically,requirement is that whenever i see 'view_Invoice' of some id,first i will see all data of that
specific id on that page and then i want to have small table below for invoice_mgmt,where i can add amount received for that specific id invoice.
*so,i want to know what fields should i add in invoice_mgmt model for relationship "
class Invoice(models.Model):
company_choice = (
('VT_India', 'VT_India'),
('VT_USA', 'VT_USA'),
)
company = models.CharField(
max_length=30, blank=True, null=True, choices=company_choice)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
project = models.ForeignKey(Allproject, on_delete=models.CASCADE)
invoice_title = models.CharField(max_length=15)
invoice_id = models.IntegerField(primary_key=True)
invoice_amount = models.IntegerField()
invoice_date = models.DateField(
blank=True, null=True)
invoice_duedate = models.DateField(
blank=True, null=True)
invoice_description = models.TextField()
def __str__(self):
return self.invoice_title
class Paymentmethod(models.Model):
paymentmethod_id = models.IntegerField(primary_key=True)
paymentmethod_name = models.CharField(max_length=15)
def __str__(self):
return self.paymentmethod_name
class Invoicemgmt(models.Model):
invoicemanagement_id = models.IntegerField(primary_key=True)
invoice_received = models.IntegerField()
date = models.DateField(
blank=True, null=True)
payment_method = models.ForeignKey(Paymentmethod, on_delete=models.CASCADE)
"So, basically i want to have multiple entries in invoice mgmt table for one specific invoice table id(one specific data)"

How to get data from two table through one query Django

** I just need one more table join in my query **
I want to get sales of logged-in users with order detail and shipping address.
I am getting sales of current user through this query but i also want get shipping address.
orderitems = OrderItem.objects.filter(
product__user=request.user, order__complete=1).order_by('-date_orderd')
Now i want to get also address, city and state from the Shippingaddress model.
I attached the models below.
this is my current result.
My models:
Order Model:
class Order(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, blank=True, null=True)
date_orderd = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False, null=True, blank=False)
transaction_id = models.CharField(max_length=200, null=True)
# product = models.ManyToManyField(OrderItem)
def __str__(self):
return str(self.id)
Order items Model:
class OrderItem(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE, blank=True, null=True)
order = models.ForeignKey(
Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_orderd = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.SET_NULL, blank=True, null=True)
price = models.FloatField(blank=True, null=True)
def __str__(self):
return str(self.product)
Shipping Address Model:
class ShippingAddress(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, blank=True, null=True)
order = models.ForeignKey(
Order, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=150)
address = models.CharField(max_length=150)
city = models.CharField(max_length=150)
state = models.CharField(max_length=150)
zipcode = models.CharField(max_length=150)
date_orderd = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
What you are looking for is "Select from multiple tables in one query with Django". You can take a look at the answers here.
Why not add another query like the one below
shp_address = ShippingAddress.objects.filter(product__user=request.user)
and if needed send to the client side as part of context, see below
context = {
'orderitems': orderitems,
'shp_address': shp_address
}

Adding assigner and assignee in Django

I am fairly new to django rest framework, and I am trying to make a model which is associated with two users, one as assigner and the other as assignee. I tried adding two different foreign keys, but it throws error. Here is my code:
job = models.ForeignKey(Job,related_name='Job',on_delete=models.CASCADE, null=True)
assigner = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
assignee = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
unit = models.ForeignKey(Unit,related_name='UnitName',on_delete=models.CASCADE, null=True)
equipment = models.ForeignKey(Equipment,related_name='EquipmentName',on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=200)
category = models.CharField(max_length=200, null=True,blank=True)
start_date = models.DateField()
end_date = models.DateField()
created_at = models.DateTimeField(auto_now_add=True,blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True,blank=True, null=True)
status = models.ForeignKey(TaskStatus, related_name='Status',on_delete=models.CASCADE)
def __str__(self):
return(self.name)
Please help