# generate the order number
import uuid
from django.db import models
from django.db.models import Sum
from django.conf import settings
from django_countries.fields import CountryField
from products.models import Product
from profiles.models import UserProfile
class Order(models.Model):
order_number = models.CharField(max_length=32, null=False, editable=False)
user_profile = models.ForeignKey(UserProfile, on_delete=models.SET_NULL,
null=True, blank=True,
related_name='orders')
full_name = models.CharField(max_length=50, null=False, blank=False)
email = models.EmailField(max_length=254, null=False, blank=False)
phone_number = models.CharField(max_length=20, null=False, blank=False)
country = CountryField(blank_label='Country *', null=False, blank=False)
postcode = models.CharField(max_length=20, null=True, blank=True)
town_or_city = models.CharField(max_length=40, null=False, blank=False)
street_address1 = models.CharField(max_length=80, null=False, blank=False)
street_address2 = models.CharField(max_length=80, null=True, blank=True)
county = models.CharField(max_length=80, null=True, blank=True)
# automatically add the date and time of the created order
date = models.DateTimeField(auto_now_add=True)
delivery_cost = models.DecimalField(
max_digits=6, decimal_places=2, null=False, default=0)
order_total = models.DecimalField(
max_digits=10, decimal_places=2, null=False, default=0)
grand_total = models.DecimalField(
max_digits=10, decimal_places=2, null=False, default=0)
original_bag = models.TextField(null=False, blank=False, default='')
stripe_pid = models.CharField(
max_length=254, null=False, blank=False, default='')
# a private method which will be used only inside of this class
def _generate_order_number(self):
"""
Generate a random, unique order number using UUID
"""
return uuid.uuid4().hex.upper()
def update_total(self):
"""
Update grand total each time a line item is added, accounting
for delivery costs.
"""
self.order_total = self.lineitems.aggregate(Sum('lineitem_total'))[
'lineitem_total__sum'] or 0
if self.order_total < settings.FREE_DELIVERY_THRESHOLD:
self.delivery_cost = self.order_total * \
settings.STANDARD_DELIVERY_PERCENTAGE / 100
else:
self.delivery_cost = 0
self.grand_total = self.order_total + self.delivery_cost
self.save()
def save(self, *args, **kwargs):
"""
Override the original save method to set the order number
if it hasn't been set already.
"""
if not self.order_number:
self.order_number = self._generate_order_number()
super().save(*args, **kwargs)
def __str__(self):
return self.order_number
class OrderLineItem(models.Model):
order = models.ForeignKey(Order, null=False, blank=False,
on_delete=models.CASCADE,
related_name='lineitems')
product = models.ForeignKey(
Product, null=False, blank=False, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False, blank=False, default=0)
lineitem_total = models.DecimalField(
max_digits=6, decimal_places=2,
null=False, blank=False, editable=False)
def save(self, *args, **kwargs):
"""
Override the original save method to set the lineitem total
and update the order total.
"""
self.lineitem_total = self.product.price * self.quantity
super().save(*args, **kwargs)
def __str__(self):
return f'SKU {self.product.sku} on order {self.order.order_number}'