Auto increament the invoice number in django backend for new invoice - python

I want to auto increament the invoice number which is 3 digits char and 4 digits number.
class Invoice:
invoice_no = models.CharField(max_length=500, null=True, blank=True, validators=[RegexValidator(regex='^[a-zA-Z0-9]*$',message='Invoice must be Alphanumeric',code='invalid_invoice number'),])
I register this model in backend. But now when i click on create invoice in admin the invoice should be auto filled. When i again click on create new invoice in admin, the invoice_number should be incremented by one and should be auto field.
Ex for Invoice number MAG0001, MAG0002, MAG0003 etc and this should be auto field in admin when i click on create new invoice.

Define a function to generate invoice number.
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
invoice_int = int(invoice_no.split('MAG')[-1])
new_invoice_int = invoice_int + 1
new_invoice_no = 'MAG' + str(new_invoice_int)
return new_invoice_no
Now use this function as default value in your model filed.
invoice_no = models.CharField(max_length=500, default=increment_invoice_number, null=True, blank=True)
This is just an idea. Modify the function to match your preferred invoice number format.

In above arulmr answer just edit char field
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
invoice_int = int(invoice_no.split('MAG')[-1])
width = 4
new_invoice_int = invoice_int + 1
formatted = (width - len(str(new_invoice_int))) * "0" + str(new_invoice_int)
new_invoice_no = 'MAG' + str(formatted)
return new_invoice_no
class Invoice(models.Model):
invoice_no = models.CharField(max_length = 500, default = increment_invoice_number, null = True, blank = True)
This will work fine.

def invoiceIncrement():
get_last_invoice_number
incremente_last_invoice_number
return next_invoice_number
class Invoice:
invoice_no = models.CharField(max_length=500, null=True, blank=True,
validators=[RegexValidator(regex='^[a-zA-Z0-9]*$',
message='Invoice must be Alphanumeric',code='invalid_invoice number'),],
default=invoiceIncrement)
Try this: there are some obvious issues:
if more than one person adds an invoice at the same time, could have collision
will need to make an extra db call each time you create a new invoice.
Also: you may want to just consider using either an auto_increment or UUID.

Maybe this code can help
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
new_invoice_no = str(int(invoice_no[4:]) + 1)
new_invoice_no = invoice_no[0:-(len(new_invoice_no))] + new_invoice_no
return new_invoice_no

def invoice_number_gen():
last_invoice = Invoice.objects.all().order_by('id').last()
last_invoice_number = last_invoice.invoice_no
#invoice number format is 'customer_name_short + number' eg: CS003
last_invoice_digits =int(last_invoice_number[2:])
#comment: slicing CS003 to get the number 003 and converting to int.
last_invoice_initials = last_invoice_number[:2]
new_invoice_digits = last_invoice_digits + 1
new_invoice_number = last_invoice_initials + str(new_invoice_digits)
return (new_invoice_number)

Related

Django : Best way to Query a M2M Field , and count occurences

class Edge(BaseInfo):
source = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_source")
target = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_target")
def __str__(self):
return '%s' % (self.label)
class Meta:
unique_together = ('source','target','label','notes')
class Node(BaseInfo):
item_type_list = [('profile','Profile'),
('page','Page'),
('group','Group'),
('post','Post'),
('phone','Phone'),
('website','Website'),
('email','Email'),
('varia','Varia')
]
item_type = models.CharField(max_length=200,choices=item_type_list,blank = True,null=True)
firstname = models.CharField(max_length=200,blank = True, null=True)
lastname = models.CharField(max_length=200,blank = True,null=True)
identified = models.BooleanField(blank=True,null=True,default=False)
username = models.CharField(max_length=200, blank=True, null=True)
uid = models.CharField(max_length=200,blank=True,null=True)
url = models.CharField(max_length=2000,blank=True,null=True)
edges = models.ManyToManyField('self', through='Edge',blank = True)
I have a Model Node (in this case a soc media profile - item_type) that has relations with other nodes (in this case a post). A profile can be the author of a post. An other profile can like or comment that post.
Question : what is the most efficient way to get all the distinct profiles that liked or commented on anothes profile's post + the count of these likes /comments.
print(Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q).values("source").annotate(c=Count('source')))
Gets me somewhere but i have the values then (id) and i want to pass the objects to my template rather then .get() all the profiles again...
Result :
Thanks in advance
I ended up with iterating over the queryset and adding the objects that i wanted in a dictionary , if the object was already in dictionary , i would count +1 and add the relation in a nested list.
This doesnt feel right but works for now.
posts = Edge.objects.filter(source = self,target__item_type='post',label='Author')
if posts:
q = Q()
for post in posts:
q = q | Q(target=post.target)
contributors = Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q)
if contributors:
for i in contributors:
if i.source.uid in results:
if i.label in results[i.source.uid]['relation']:
pass
else:
results[i.source.uid]["relation"].append(i.label)
if 'post' in results[i.source.uid]:
results[i.source.uid]['post'].append(i.target)
else:
results[i.source.uid]['post']=[i.target]
else:
results[i.source.uid] = {'profile' : i.source , 'relation':[i.label],'post':[i.target]}

Override ChoiceField choice attribute with for loop in Django views

I m trying to override ChoiceField in forms in which i can loop through specific object in my views,
But i Failed cause i only get in the template form only the last item in the list..
need some help to get all the choices i need from this object.
models.py
class TourPackageBuyer(models.Model):
tour = models.ForeignKey(TourPackage, on_delete=models.CASCADE, null =True) production
number_choice = [(i,i) for i in range(6)]
number_choice_2 = [(i,i) for i in range(18)]
number_choice_3 = [(i,i) for i in range(60)]
user = models.CharField(settings.AUTH_USER_MODEL, max_length=200)
num_of_adults = models.PositiveIntegerField(default=0, choices= number_choice_2, null=True)
num_of_children = models.PositiveIntegerField(default=0, choices= number_choice_3, null=True)
hotel = models.ManyToManyField(PackageHotel, blank=True)### thats the field
forms.py
class TourPackageBuyerForm(ModelForm):
class Meta:
model = TourPackageBuyer
date = datetime.date.today().strftime('%Y')
intDate = int(date)
limitDate = intDate + 1
YEARS= [x for x in range(intDate,limitDate)]
# YEARS= [2020,2021]
Months = '1',
# fields = '__all__'
exclude = ('user','tour','invoice','fees', 'paid_case')
widgets = {
'pickup_date': SelectDateWidget(empty_label=("Choose Year", "Choose Month", "Choose Day")),
'hotel': Select(),
# 'pickup_date': forms.DateField.now(),
}
hotel = forms.ChoiceField(choices=[]) ### Thats the field i m trying to override
views.py
def TourPackageBuyerView(request, tour_id):
user = request.user
tour = TourPackage.objects.get(id=tour_id)
tour_title = tour.tour_title
hotels = tour.hotel.all()
form = TourPackageBuyerForm(request.POST or None, request.FILES or None)
### im looping through specific items in the model in many to many field
for h in hotels:
form.fields['hotel'].choices = (h.hotel, h.hotel), ### when this loop it just give the last item in the form in my template!!
You are reassigning the value of choices every time through the loop, so you'll only get the last value you assign once the loop is finished.
You can fix this by replacing this:
for h in hotels:
form.fields['hotel'].choices = (h.hotel, h.hotel),
With this list comprehension:
form.fields['hotel'].choices = [(h.hotel, h.hotel) for h in hotels]
or if you want a tuple as output you can do:
form.fields['hotel'].choices = tuple((h.hotel, h.hotel) for h in hotels)

New item checks for the missing ID and create it

IS there a method to make Django check for missing id number and create a new item in this slot, instead of making it with a new id.
Here is what am trying to do
I have the model :
class BuyInvoice(models.Model):
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=PROTECT)
branch = models.ForeignKey(Branch, on_delete=PROTECT)
supplier = models.ForeignKey(Supplier, on_delete=PROTECT)
total = models.PositiveIntegerField(default=0)
is_done = models.BooleanField(default=False)
is_canceled = models.BooleanField(default=False)
def __str__(self):
return 'فاتورة بيع رقم ' + str(self.pk)
whenever I add a new item to it it takes the auto-generated id as 1, 2, 3, 4, 5
now if I deleted the item with the id 3, then I try to create new item I want it to be added to the id of 3 instead of 6
I did it manually by looping over items and find a gap to fill :
check_for_gap = BuyInvoice.objects.all()
number = 1
for item in check_for_gap:
if item.id != number:
new_invoice = BuyInvoice.objects.create(user=user, branch=branch, supplier=supplier_obj, id=number)
return redirect('invoice_buy_details', pk=new_invoice.id)
else:
number += 1

Create error message datefield

I want to create an error message for following form:
class ExaminationCreateForm(forms.ModelForm):
class Meta:
model = Examination
fields = ['patient', 'number_of_examination', 'date_of_examination']
Models:
class Patient(models.Model):
patientID = models.CharField(max_length=200, unique=True, help_text='Insert PatientID')
birth_date = models.DateField(auto_now=False, auto_now_add=False, help_text='YYYY-MM-DD')
gender = models.CharField(max_length=200,choices=Gender_Choice, default='UNDEFINED')
class Examination(models.Model):
number_of_examination = models.IntegerField(choices=EXA_Choices)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
date_of_examination = models.DateField(auto_now=False, auto_now_add=False, help_text='YYYY-MM-DD')
Every Patient has 2 Examinations (number of examination = Choices 1 or 2) and the error message should be activated when the date of the second examination < date of the first examination. Something like this:
Solution: `
def clean_date_of_examination(self):
new_exam = self.cleaned_data.get('date_of_examination')
try:
old_exam = Examination.objects.get(patient=self.cleaned_data.get('patient'))
except Examination.DoesNotExist:
return new_exam
if old_exam:
if old_exam.date_of_examination > new_exam:
raise forms.ValidationError("Second examination should take place after first examination")
return new_exam`
def clean_date_of_examination(self):
new_exam = self.cleaned_data.get('date_of_examination')
old_exam = Examination.objects.get(patient = self.cleaned_data.get('Patient'))
if old_exam:
if old_exam.date_of_examination > new_exam.date_of_examination:
raise forms.ValidationError("Second examination should take place after first examination")
return data
def clean_date_of_examination(self):
# Where 'data' is used?
date_of_exam = self.cleaned_data['date_of_examination']
try:
pat1 = Patient.object.get(examination__number_of_examination=1, date_of_examination=date_of_exam)
except Patiens.DoesNotExist:
# Patient 1 with given query doesn't exist. Handle it!
try:
pat2 = Patient.object.get(examination__number_of_examination=2, date_of_examination=date_of_exam)
except Patiens.DoesNotExist:
# Patient 2 with given query doesn't exist. Handle it!
if pat2.date_of_examination < pat1.date_of_examination:
raise forms.ValidationError("Second examination should take place after first examination")`
return data`

How do I display Django data from a related model of a related model?

I am trying to display data from several models that are related together through a QuerySet. My ultimate goal is to display some information from the Site model, and some information from the Ppack model, based on a date range filter of the sw_delivery_date in the Site model.
Here are my models:
class Site(models.Model):
mnemonic = models.CharField(max_length = 5)
site_name = models.CharField(max_length = 100)
assigned_tech = models.ForeignKey('Person', on_delete=models.CASCADE, null = True, blank = True)
hw_handoff_date = models.DateField(null = True, blank = True)
sw_delivery_date = models.DateField(null = True, blank = True)
go_live_date = models.DateField(null = True, blank = True)
web_url = models.CharField(max_length = 100, null = True, blank = True)
idp_url = models.CharField(max_length = 100, null = True, blank = True)
def __str__(self):
return '(' + self.mnemonic + ') ' + self.site_name
class Ring(models.Model):
ring = models.IntegerField()
def __str__(self):
return "6." + str(self.ring)
class Ppack(models.Model):
ppack = models.IntegerField()
ring = models.ForeignKey('Ring', on_delete=models.CASCADE)
def __str__(self):
return str(self.ring) + " pp" + str(self.ppack)
class Code_Release(models.Model):
Inhouse = 'I'
Test = 'T'
Live = 'L'
Ring_Location_Choices = (
(Inhouse, 'Inhouse'),
(Test, 'Test'),
(Live, 'Live'),
)
site_id = models.ForeignKey('Site', on_delete=models.CASCADE)
type = models.CharField(max_length = 1, choices = Ring_Location_Choices, blank = True, null = True)
release = models.ForeignKey('Ppack', on_delete=models.CASCADE)
def __str__(self):
return "site:" + str(self.site_id) + ", " + self.type + " = " + str(self.release)
If I use the following,
today = datetime.date.today()
future = datetime.timedelta(days=60)
new_deliveries = Site.objects.select_related().filter(sw_delivery_date__range=[today, (today + future)])
I can get all of the objects in the Site model that meet my criteria, however, because there is no relation from Site to Code_Release (there's a one-to-many coming the other way), I can't get at the Code_Release data.
If I run a for loop, I can iterate through every Site returned from the above query, and select the data from the Code_Release model, which allows me to get the related data from the Ppack and Ring models.
site_itl = {}
itl = {}
for delivery in new_deliveries:
releases = Code_Release.objects.select_related().filter(site_id = delivery.id)
for rel in releases:
itl[rel.id] = rel.release
site_itl[delivery.id] = itl
But, that seems overly complex to me, with multiple database hits and possibly a difficult time parsing through that in the template.
Based on that, I was thinking that I needed to select from the Code_Release model. That relates back to both the Site model and the Ppack model (which relates to the Ring model). I've struggled to make the right query / access the data in this way that accomplishes what I want, but I feel this is the right way to go.
How would I best accomplish this?
You can use RelatedManager here. When you declare ForeignKey, Django allows you to access reverse relationship. To be specific, let's say that you have multiple code releases that are pointing to one specific site. You can access them all via site object by using <your_model_name_lowercase>_set attribute. So in your case:
site.code_release_set.all()
will return QuerySet of all code release objects that have ForeignKey to object site
You can access the Releases from a Site object. First, you can put a related_name to have a friendly name of the reverse relation between the models:
site_id = models.ForeignKey('Site', on_delete=models.CASCADE, related_name="releases")
and then, from a Site object you can make normal queries to Release model:
site.releases.all()
site.releases.filter(...)
...

Categories

Resources