Reputation: 404
Please forgive me if this has already been asked
I am following a course online, albeit 3 years old, so somethings have been updated since then
However datetime seems to be roughly the same from what I can see.
The problem arises when we use timedelta to filter all the sales in the last month
I have added some test sales over the weeks and when I tried to filter it down to the last 48 hours, nothing
with a bit of testing i went back 12 days (as of this question and a list of items sold back on the 20th February showed up but nothing sooner.
I went into the admin and updated one of them and refreshed the page. and it disappeared completely
Can anyone provide any insight as to what i am missing?
If you need more information please say:
Models.py
from decimal import Decimal
import datetime
from django.conf import settings
from django.db import models
from django.db.models import Count, Sum, Avg
from django.db.models.signals import pre_save, post_save
from django.urls import reverse
from django.utils import timezone
from addresses.models import Address
from billing.models import BillingProfile
from carts.models import Cart
from ecommerce.utils import unique_order_id_generator
from products.models import Product
ORDER_STATUS_CHOICES = (
('created', 'Created'),
('paid', 'Paid'),
('shipped', 'Shipped'),
('refunded', 'Refunded'),
)
class OrderManagerQuerySet(models.query.QuerySet):
def recent(self):
return self.order_by("-updated", "-timestamp")
def by_date(self):
now = timezone.now() - datetime.timedelta(days=12)
return self.filter(updated__day__gte=now.day)
def totals_data(self):
return self.aggregate(Sum("total"), Avg("total"))
def cart_data(self):
return self.aggregate(Sum("cart__products__price"), Avg("cart__products__price"), Count("cart__products"))
def by_status(self, status="shipped"):
return self.filter(status=status)
def not_refunded(self):
return self.exclude(status='refunded')
def by_request(self, request):
billing_profile, created = BillingProfile.objects.new_or_get(request)
return self.filter(billing_profile=billing_profile,)
def not_created(self):
return self.exclude(status='created')
class OrderManager(models.Manager):
def get_queryset(self):
return OrderManagerQuerySet(self.model, using=self._db)
def by_request(self, request):
return self.get_queryset().by_request(request)
def new_or_get(self, billing_profile, cart_obj):
created = False
qs = self.get_queryset().filter(
billing_profile=billing_profile,
cart=cart_obj,
active=True,
status='created'
)
if qs.count() == 1:
obj = qs.first()
else:
obj = self.model.objects.create(
billing_profile=billing_profile,
cart=cart_obj
)
created = True
return obj, created
class Order(models.Model):
billing_profile = models.ForeignKey(BillingProfile, null=True, blank=True, on_delete=models.CASCADE)
order_id = models.CharField(max_length=120, blank=True)
shipping_address = models.ForeignKey(Address, related_name="shipping_address", null=True, blank=True, on_delete=models.CASCADE)
billing_address = models.ForeignKey(Address, related_name="billing_address", null=True, blank=True, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
status = models.CharField(max_length=120, default='created', choices=ORDER_STATUS_CHOICES)
shipping_total = models.DecimalField(default=5.99, max_digits=100, decimal_places=2)
total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
active = models.BooleanField(default=True)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.order_id
objects = OrderManager()
class Meta:
ordering = ['-timestamp', '-updated']
def get_absolute_url(self):
return reverse("orders:detail", kwargs={'order_id': self.order_id})
def get_status(self):
if self.status == "refunded":
return "Refunded order"
elif self.status == "shipped":
return "Shipped"
return "Shipping Soon"
def update_total(self):
cart_total = self.cart.total
shipping_total = self.shipping_total
new_total = Decimal(cart_total)+Decimal(shipping_total)
formatted_total = format(new_total, '.2f')
print(type(new_total))
self.total = formatted_total
self.save()
return new_total
def check_done(self):
shipping_address_required = not self.cart.is_digital
shipping_done = False
if shipping_address_required and self.shipping_address:
shipping_done = True
elif shipping_address_required and not self.shipping_address:
shipping_done = False
else:
shipping_done = True
billing_profile = self.billing_profile
billing_address = self.billing_address
total = self.total
if billing_profile and shipping_done and billing_address and total > 0:
return True
return False
def update_purchases(self):
for p in self.cart.products.all():
obj, create = ProductPurchase.objects.get_or_create(
order_id = self.order_id,
product = p,
billing_profile= self.billing_profile,
)
return ProductPurchase.objects.filter(order_id = self.order_id).count()
def mark_paid(self):
if self.status != 'paid':
if self.check_done():
self.status = "paid"
self.save()
self.update_purchases()
return self.status
def pre_save_create_order_id(sender, instance, *args, **kwargs):
if not instance.order_id:
instance.order_id = unique_order_id_generator(instance)
qs= Order.objects.filter(cart=instance.cart).exclude(billing_profile=instance.billing_profile)
if qs.exists():
qs.update(active=False)
pre_save.connect(pre_save_create_order_id, sender=Order)
def post_save_cart_total(sender, instance, created, *args, **kwargs):
if not created:
cart_obj = instance
cart_total = cart_obj.total
cart_id = cart_obj.id
qs = Order.objects.filter(cart__id=cart_id)
if qs.count() ==1:
order_obj = qs.first()
order_obj.update_total()
post_save.connect(post_save_cart_total,sender=Cart)
def post_save_order(sender, instance, created, *args, **kwargs):
print("running")
if created:
print("updating...first")
instance.update_total()
post_save.connect(post_save_order,sender=Order)
class ProductPurchaseQuerySet(models.query.QuerySet):
def active(self):
return self.filter(refunded=False)
def digital(self):
return self.filter(product__is_digital=True)
def by_request(self, request):
billing_profile, created = BillingProfile.objects.new_or_get(request)
return self.filter(billing_profile=billing_profile,)
class ProductPurchaseManager(models.Manager):
def get_queryset(self):
return ProductPurchaseQuerySet(self.model, using=self._db)
def all(self):
return self.get_queryset().active()
def digital(self):
return self.get_queryset().active().digital()
def by_request(self, request):
return self.get_queryset().by_request(request)
def products_by_id(self, request):
qs = self.by_request(request).digital()
ids_ = [x.product.id for x in qs]
return ids_
def products_by_request(self, request):
ids_ = self.products_by_id(request)
product_qs = Product.objects.filter(id__in=ids_).distinct()
return product_qs
class ProductPurchase(models.Model):
order_id = models.CharField(max_length=120)
billing_profile = models.ForeignKey(BillingProfile, on_delete=models.CASCADE) # billingprofile.productpurchase_set.all()
product = models.ForeignKey(Product, on_delete=models.CASCADE) # product.productpurchase_set.count()
refunded = models.BooleanField(default=False)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = ProductPurchaseManager()
def __str__(self):
return self.product.title
Views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Count, Sum, Avg
from django.http import HttpResponse
from django.views.generic import TemplateView
from django.shortcuts import render
from orders.models import Order
class SalesView(LoginRequiredMixin, TemplateView):
template_name = 'analytics/sales.html'
def dispatch(self, *args, **kwargs):
user = self.request.user
if not user.is_staff:
return render(self.request, "401.html", {})
return super(SalesView, self).dispatch(*args, **kwargs)
def get_context_data(self, *args, **kwargs):
context = super(SalesView, self).get_context_data(*args, **kwargs)
qs = Order.objects.all().by_date()
context['orders'] = qs
context['recent_orders'] = qs.recent().not_refunded()
context['recent_orders_data'] = context['recent_orders'].totals_data()
context['recent_orders_cart_data'] = context['recent_orders'].cart_data()
context['shipped_orders'] = qs.recent().not_refunded().by_status("shipped")
context['shipped_orders_data'] = context['shipped_orders'].totals_data()
context['paid_orders'] = qs.recent().not_refunded().by_status("paid")
context['paid_orders_total'] = context['paid_orders'].totals_data()
return context
Sales.html
{% extends "base.html" %}
{% block content%}
<div class="row">
<div class="col-12">
<h1>Sales Data</h1>
</div>
</div>
<div class="row">
<div class="col">
<p>Recent Toal: £{% if recent_orders_data.total__sum %} {{ recent_orders_data.total__sum }}{% else %}0 {% endif %}</p>
<ol>
{% for order in recent_orders %}
<li>{{ order.order_id}}
{{ order.total}}
{{ order.updated}} </li>
{% endfor %}
</ol>
</div>
<div class="col">
<p>Shipped Total: £{% if shipped_orders_data.total__sum %}{{ shipped_orders_data.total__sum }}{% else %}0{% endif %}</p>
<ol>
{% for order in shipped_orders %}
<li>{{ order.order_id}}
{{ order.total}}
{{ order.updated}}</li>
{% endfor %}
</ol>
</div>
<div class="col">
<p>Paid Totals: £{% if shipped_orders_data.total__sum %}{{ paid_orders_total.total__sum }}{% else %}0{% endif %}</p>
<ol>
{% for order in paid_orders %}
<li>{{ order.order_id}}
{{ order.total}}
{{ order.updated}}</li>
{% endfor %}
</ol>
</div>
</div>
{% endblock %}
Upvotes: 0
Views: 76
Reputation: 40
The following should work fine:
now = timezone.now().date() - datetime.timedelta(days=12)
return self.filter(updated__date__gte=now)
Upvotes: 1
Reputation: 921
In your filter by_date method you are using a filter on the day not the date. This won't help as it'll return the day of the month. So if the date was 2020-03-11 it would return 29 for now.day. If you change .day for .date() as well as updated__day__gte for updated__date__gte it should be okay
def by_date(self):
now = timezone.now() - datetime.timedelta(days=12)
return self.filter(updated__date__gte=now.date())
Upvotes: 3