I am trying to calculate the total cost of all the services with taxes in the bill using a single query. I don't understand where I am going wrong.
MODELS:
class Bill(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
number = models.CharField(max_length=100, blank=True)
class BillService(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
bill = models.ForeignKey(Bill, related_name='billservices', on_delete=models.CASCADE)
service = models.ForeignKey(Service, on_delete=models.CASCADE)
class Service(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
business = models.ForeignKey(Business, related_name='services', on_delete=models.CASCADE, blank=True)
short_code = models.IntegerField(default=0)
class ServiceTax(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name="servicetaxes")
tax = models.ForeignKey(Tax, on_delete=models.CASCADE)
class Tax(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
business = models.ForeignKey(Business, related_name='taxes', on_delete=models.CASCADE)
name = models.CharField(max_length=50)
tax = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(100)], default=0)
MY QUERY TO GET A SINGLE VALUE, THAT IS TOTAL COST OF THE BILL
value = bill.billservices.all()
.annotate(sum_of_taxed_percentages=Subquery(
Service.objects.filter(billservice=OuterRef('id'))
.annotate(total_tax_value=Subquery(
ServiceTax.objects.filter(service=OuterRef('id'))
.values('tax')
.annotate(total_tax=Sum('tax__tax', output_field=FloatField()))
.values('total_tax')
)).annotate(taxed_value=F('price') + ((F('price') * F('total_tax_value')) / 100))
.values('taxed_value')
.annotate(total_services_taxed_value=Sum('taxed_value', output_field=FloatField()))
.values('total_services_taxed_value')
))
print(value[0].sum_of_taxed_percentages)
ERROR:
'ManyToOneRel' object has no attribute 'select_format'
If this is where you're calculating the percentage:
taxed_value=F('price') + ((F('price') * F('total_tax_value')) / 100)
on this trench:
((F('price') * F('total_tax_value')) / 100
i think you need to change some parentheses:
(F('price') * (F('total_tax_value') / 100))
because you first need to divide the percentage you have stored to 100 and then you multiply that by the price of the object to then sum to the current value of it:
taxed_value=F('price') + (F('price') * (F('total_tax_value') / 100))
Check if it works, i'm not sure, it seems that is a simple formula problem...
After many trial and errors, I found the solution.
service_tax = ServiceTax.objects.filter(service=OuterRef('service')) \
.values('tax__tax')
value = bill.billservices.all() \
.annotate(service_taxes=SQSum(service_tax)) \
.annotate(service_price=F('service__price')) \
.aggregate(total=Sum(F('service_price') + ((F('service_price') * F('service_taxes')) / 100),
output_field=FloatField()))
print(value)
class SQSum(Subquery):
template = "(SELECT SUM(tax) FROM (%(subquery)s) _sum)"
output_field = models.FloatField()
Related
I have Two models :
class MonthSalary(models.Model):
month = models.DateField(null=True)
def __str__(self):
return str(self.month.year) + '/' + str(self.month.month)
class SalaryPerMonth(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
salary_month = models.ForeignKey(MonthSalary, null=True, on_delete=models.CASCADE)
main_salary_per_month = models.PositiveIntegerField(default=0, null=True)
net_salary_per_month = models.PositiveIntegerField(default=0, null=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=["user", "salary_month"], name="all_keys_unique_together")]
def __str__(self):
return str(self.user.employeedetail.empcode) + ' ' + str(self.net_salary_per_month) + ' USD' + str(
self.salary_month)
In Views I can query all user salaries with :
user = request.user
salary_per_month = SalaryPerMonth.objects.filter(user=user)
In MonthSalary model I added a bunch of months\years not in order Ex "2022-2,2022-4,2022-1,2021-4" when I filter user's salary by ordering the date "related salary_month field" like so :
salary_per_month = SalaryPerMonth.objects.filter(user=user).order_by('salary_month')
It's not in order.
Q1 = How how filter by Year ?
Q2 = How to order by month ?
So this is the answer to part one of my question "Q2" ordering by Month
All I did is add Meta class:
class Meta:
class MonthSalary(models.Model):
month = models.DateField(null=True)
class Meta:
ordering = ['-month']
class SalaryPerMonth(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
salary_month = models.ForeignKey(MonthSalary, null=True, on_delete=models.CASCADE)
main_salary_per_month = models.PositiveIntegerField(default=0, null=True)
net_salary_per_month = models.PositiveIntegerField(default=0, null=True)
class Meta:
ordering = ['-salary_month']
class Order(models.Model):
pass
class OrderItems(models.Model):
order = models.ForiegnKey(Order, related_name="items")
name = models.CharField(max_length=255, null=False)
quantity = models.DecimalField(max_digits=5, decimal_places=2)
supplier = models.CharField(max_length=255, null=False)
purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
trade_price = models.DecimalField(max_digits=10, decimal_places=2,blank=False, null=False , default = 0.00)
retail_price = models.DecimalField(max_digits=10, decimal_places=2)
class OrderItemSalesTax(models.Model):
order_item = models.ForiegnKey(OrderItems, related_name="sales_tax")
name = models.CharField(max_length=255)
percentage = models.DecimalField(max_digits=6, decimal_places=2)
class OrderItemDiscount(models.Model):
order_item = models.OneToOneField(OrderItem, primary_key=True, on_delete=models.CASCADE, related_name='discount')
name = models.CharField(max_length=255)
discount = models.DecimalField(max_digits=6, decimal_places=2)
in_percentage = models.BooleanField()
I am using this query to calculate the total amount, but also deducting discount and adding Sales tax.
Sum(F('items__sales_tax__percentage')) value is 25, and I have verified it, querying the database. Right now I have only One order and two Items and Items have two Sales Taxes and One Discount
I am trying to Sum the Sales taxes to apply on discounted price, but I am getting the wrong result results. If I manually write 25 by replacing Sum(F('items__sales_tax__percentage')) then results are correct, is there anything wrong with my query ?
Order.objects.filter(customer__zone__distribution=get_user_distribution(request.user.id))\
.annotate(
trade_price=Sum(F('items__trade_price') * F('items__quantity')),
tax = Sum(F('items__sales_tax__percentage')),
discounted_price = F('trade_price') * ExpressionWrapper(0.01 * (100 - Sum(F('items__discount__discount'))), output_field=DecimalField()),
total = F('discounted_price') + F('discounted_price') * Sum(F('items__sales_tax__percentage')) / 100
)
I have the code which calculates the sum just fine, now my question is it possible to multiple each price by quantity and then get the total sum after that in a cart on my website. I have tried with all of my logic but i have failed. The idea is to get the price of an item added to cart and multiply it by quantity and then get the total.
Here is my cart mode. models.py:
#cart model
class Cart(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
number_of_items = models.IntegerField(default=0)
user = models.ForeignKey(User, on_delete=models.CASCADE)
added_datetime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.item.name
#Item model
class Item(models.Model):
CONDITION = (
('new', 'new'),
('used', 'used'),
('not applicable', 'not applicable'),
)
name = models.CharField(max_length=250)
owner = models.CharField(max_length=250, default='Ludocs-emark')
category = models.ForeignKey(ItemCategories, on_delete=models.CASCADE)
sub_category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
Condition = models.CharField(max_length=250, null=True, choices=CONDITION)
price= models.IntegerField(default=0)
number_of_items = models.IntegerField(blank=True)
specification_one = models.CharField(max_length=250, blank=True)
specification_two = models.CharField(max_length=250, blank=True)
specification_three = models.CharField(max_length=250, blank=True)
specification_four = models.CharField(max_length=250, blank=True)
specification_five = models.CharField(max_length=250, blank=True)
specification_six = models.CharField(max_length=250, blank=True)
available_colors = models.CharField(max_length=250, blank=True)
description = RichTextField()
thumbnail = models.ImageField(default='default.png', upload_to='images/')
image_one = models.ImageField(upload_to='images/')
image_two = models.ImageField(upload_to='images/')
image_three = models.ImageField(upload_to='images/')
image_four = models.ImageField(upload_to='images/')
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
views.py file that i used to calculate the sum:
#This is the file where that i want to use to get the items added in cart and then multiply each by it's quantity and then get the total of the calculations when multiplied.
cart_sum = Cart.objects.filter(user=request.user).aggregate(Sum('item__price')).get('item__price__sum')
Yes, You can do that.
Try this
cart_sum = Cart.objects.filter(user=request.user).aggregate(Sum('item__price', field='item__price * number_of_items')).get('item__price__sum')
Assuming number_of_items as the quantity for the item from the Cart model.
Also you can return a total value so that if this gives any error for two different fields then you can do this
cart_sum = Cart.objects.filter(user=request.user).aggregate(total_price=Sum('item__price', field='item__price * number_of_items')).get('total_price')
I already calculate, the total of one consummation, now i just want to sum all the consumations
class Consommation(models.Model):
food = models.ManyToManyField(Food)
consomme_le = models.DateTimeField(default=timezone.now, editable=False)
vipcustomer = models.ForeignKey(VipCustomer, models.CASCADE, null=True,
blank=True, verbose_name='Client prestigieux',
related_name='vip_consommations')
to calculate one consummation:
def total(self):
return self.food.aggregate(total=Sum('price'))['total']
Food class :
class Food(models.Model):
nom = models.CharField(max_length=100, verbose_name='Mon menu')
price = models.PositiveIntegerField(verbose_name='Prix')
category = models.ForeignKey(FoodCategory, models.CASCADE,
verbose_name="Categorie")
vipcustomer class:
class VipCustomer(models.Model):
first_name = models.CharField(max_length=150, verbose_name='Prénom')
last_name = models.CharField(max_length=100, verbose_name='Nom')
matricule = models.PositiveIntegerField(verbose_name='Matricule',
default=0)
adresse = models.CharField(max_length=200, verbose_name='Adresse',
blank=True)
telephone = PhoneField()
company = models.CharField(max_length=100, verbose_name='La société')
service = models.CharField(max_length=100, verbose_name='Service',
null=True, blank=True)
numero_badge = models.IntegerField(verbose_name='Numero du badge',
null=True, blank=True)
My goal is to calculate the total of all the consummations.
For a given VipCustomers, you can query with:
my_vip_customer.vip_consommations.aggregate(
total=Sum('food__price')
)['total']
We thus aggregate over the set of related Consommations, and we then aggregate over all the related Foods of these Consommations, and their corresponding price.
If there are no related Consommations, or no related Foods of these Consommations, then the sum will return None, instead of 0. We can add or 0 to convert a None to an 0 here:
my_vip_customer.vip_consommations.aggregate(
total=Sum('food__price')
)['total'] or 0
or for all Customers, we can annotate this with:
VipCustomer.objects.annotate(
total=Sum('vip_consommations__food__price')
)
Here the VipCustomers that arise from this, will have an extra attribute .total that contains the sum of the prices of the related Foods of the related Consommations.
model.py
class Fatture(models.Model):
numero = models.CharField(max_length=30, null=True, blank=True)
data = models.DateField()
iva = models.PositiveIntegerField()
commissione = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
class Ddts(models.Model):
fattura = models.ForeignKey('Fatture')
class DdtsArticoli(models.Model):
ddt = models.ForeignKey('Ddts')
articolo = models.ForeignKey('Articoli')
quantita = models.DecimalField(max_digits=6, decimal_places=2)
prezzo = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
colli = models.PositiveIntegerField()
I have to make a query that calculate this total:
aggregate table DdtsArticoli SUM(quantita * prezzo)
aggregate table DdtsArticoli ((quantita * prezzo) / (1 + (iva of table
Fatture)/100 ))
resut of 1) - result of 2)
See the Django docs on aggregation for detail but 1. should be something like:
from django.db.models import Sum
DdtsArticoli.objects.all().aggregate(
your_key=Sum(F('quantita') * F('prezzo'), output_field=FloatField()))
Number 2. is no aggragation, you can simply calculate it:
(obj.quantita * obj.prezzo) / (1 + (obj.ddt.fattura.iva/100.0))
Where obj is your object aka. your database row.
Number 3. should be trivial then.