#!/usr/bin/env python """ Django models for cart """ # -*- coding: utf-8 -*- from decimal import Decimal from django.db import models from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User from .managers import CartManager, CartItemManager from pbp_core.utils import temp_code, pbp_converter class Cart(models.Model): """ Shopping cart """ # basically session_key cart_id = models.CharField(max_length=50, db_index=True) owner = models.ForeignKey(User, related_name="cart", null=True, blank=True) creation_date = models.DateTimeField(auto_now_add=True) last_update = models.DateTimeField(auto_now_add=True, auto_now=True) checked_out = models.BooleanField(default=False) objects = CartManager() class Meta: """ Django model meta class """ verbose_name = _("Cart") verbose_name_plural = _("Carts") ordering = ("-creation_date",) def __unicode__(self): """ unicode name of model """ return u"Cart: {0}".format(unicode(self.cart_id)) @property def has_items(self): """ is the cart empty?""" return self.item_count > 0 @property def cart_items(self): """ return all cart items""" return self.items.all() @property def item_count(self): """ number of items """ return self.items.count() @property def cart_shipping_total(self): """ Total shipping cost""" price = Decimal(0.0) for item in self.cart_items: price = price + item.total_shipping_cost return price @property def cart_subtotal(self): """ cart subtotal""" price = Decimal(0.0) for item in self.cart_items: price = price + item.total_price return price @property def cart_total(self): """ total cart cost""" return self.cart_subtotal + self.cart_shipping_total @property def purchase_description(self): """ the purchase description for carts """ description = "" for item in self.cart_items: description = description + "
" + item.by_line return description @property def buyer_id(self): """ the buyer for the person who created the cart""" if self.owner: return self.owner.pk return None class CartItemGiftDetail(models.Model): """ Cart Item gift detail """ first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) company = models.CharField(max_length=30, blank=True, null=True) address1 = models.CharField(max_length=30) address2 = models.CharField(max_length=30, blank=True, null=True) city = models.CharField(max_length=30) region = models.CharField(max_length=30) phone = models.CharField(max_length=30) country = models.CharField(max_length=30) country_other = models.CharField(max_length=30) postal_code = models.CharField(max_length=30) plus_four = models.CharField(max_length=4) email = models.CharField(max_length=30) bill_on_renewal = models.CharField(max_length=10) gift_card_delivery = models.CharField(max_length=10) message = models.CharField(max_length=72, null=True, blank=True) class CartItem(models.Model): """ Cart items """ cart = models.ForeignKey(Cart, verbose_name=_("cart"), related_name="items") quantity = models.PositiveIntegerField(verbose_name=_("quantity")) # need a unique value we can reference when editing # that won't be easy to spoof cart_token = models.CharField(_("Cart Token"), max_length=255, db_index=True) # product as generic relation content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() gift_detail = models.OneToOneField(CartItemGiftDetail, null=True, blank=True) account_number = models.CharField(max_length=7, null=True, blank=True) class Meta: """ Model meta class""" verbose_name = _("item") verbose_name_plural = _("items") ordering = ("cart",) objects = CartItemManager() def __unicode__(self): """ unicode repr of class """ return "Item in cart: " + unicode(self.product) def save(self, *args, **kwargs): """ We need to set the cart_token to make sure it is unique """ # This check should be skipped since cart_token is required. # keeping it in for now to clean up stale data if not self.cart_token: if not self.pk: self.cart_token = temp_code() super(CartItem, self).save(*args, **kwargs) # saving with force_insert twice leads to sad kwargs.pop("force_insert", None) encode_value = pbp_converter.encode(str(self.pk)) self.cart_token = "P%s" % encode_value super(CartItem, self).save(*args, **kwargs) @property def is_gift(self): """ is this a gift? """ if self.gift_detail: return True return False @property def image(self): """ get the image """ return self.product.image @property def unit_price(self): """ unit price """ return self.product.price @property def name(self): """ name """ return self.product.title @property def description(self): """ description """ return self.product.description @property def by_line(self): """ get the byline""" return "{0} {1}".format(self.name, self.description) @property def sku(self): """ get the sku """ return self.product.sku @property def total_shipping_cost(self): """ Shipping costs. If there is just one item take the shipping_cost from the product, if there is more then one, for each item after the first one, the shipping cost is shipping_cost_multiple for each item total them together to get the total shipping cost """ initial_cost = self.product.shipping_cost extra_item_costs = self.product.shipping_cost_multiple if self.quantity == 0: return 0.0 if self.quantity == 1: return initial_cost elif self.quantity > 1: return initial_cost + ((self.quantity - 1) * extra_item_costs) @property def total_price(self): """ total price """ return self.quantity * self.unit_price @property def sub_total(self): """ price including shipping """ return self.total_price + self.total_shipping_cost def get_product(self): """ get the product """ return self.content_type.get_object_for_this_type(id=self.object_id) def set_product(self, product): """ set the product """ self.content_type = ContentType.objects.get_for_model(type(product)) self.object_id = product.pk product = property(get_product, set_product)