from decimal import Decimal from django.contrib.localflavor.us.us_states import STATE_CHOICES from django.db import models from django.contrib.auth.models import User from django_countries.countries import COUNTRIES from billing.models import GCNewOrderNotification, AmazonFPSResponse from catalog.models import Item from pbp_core.models import TimeStampedModel from . import constants from . import managers class BaseOrderInfo(TimeStampedModel): """ base class for storing customer order information """ class Meta: abstract = True # contact info email = models.EmailField(max_length=50, null=True, blank=True) phone = models.CharField(max_length=20, null=True, blank=True) # shipping information shipping_name = models.CharField(max_length=50, null=True, blank=True) shipping_address_1 = models.CharField(max_length=50, null=True, blank=True) shipping_address_2 = models.CharField(max_length=50, null=True, blank=True) shipping_city = models.CharField(max_length=50, null=True, blank=True) shipping_state = models.CharField(max_length=2, null=True, blank=True) shipping_country = models.CharField(max_length=50, null=True, blank=True) shipping_zip = models.CharField(max_length=10, null=True, blank=True) # billing information billing_name = models.CharField(max_length=50, null=True, blank=True) billing_address_1 = models.CharField(max_length=50, null=True, blank=True) billing_address_2 = models.CharField(max_length=50, null=True, blank=True) billing_city = models.CharField(max_length=50, null=True, blank=True) billing_state = models.CharField(max_length=2, null=True, blank=True) billing_country = models.CharField(max_length=50, null=True, blank=True) billing_zip = models.CharField(max_length=10, null=True, blank=True) class Order(BaseOrderInfo): """ model class for storing a customer order instance """ # each individual status INIT = 0 SUBMITTED = 1 PROCESSED = 2 SHIPPED = 3 CANCELLED = 4 # set of possible order statuses ORDER_STATUSES = ( (INIT, "Initialized"), (SUBMITTED, "Submitted"), (PROCESSED, "Processed"), (SHIPPED, "Shipped"), (CANCELLED, "Cancelled"), ) # order info date = models.DateTimeField(auto_now_add=True) status = models.IntegerField(choices=ORDER_STATUSES, default=INIT) ip_address = models.IPAddressField(null=True, blank=True) last_updated = models.DateTimeField(auto_now=True) user = models.ForeignKey(User, null=True, blank=True) transaction_id = models.CharField(max_length=20, null=True, blank=True) cart_id = models.CharField(max_length=50, null=True, blank=True) objects = managers.OrderManager() def __unicode__(self): return u"Order #" + str(self.id) @property def get_status(self): for enum, value in self.ORDER_STATUSES: if self.status == enum: return value @property def has_items(self): return self.item_count > 0 @property def item_count(self): return self.items.count() @property def order_items(self): return self.items.all() @property def subscription_items(self): """ return only the subscriptions """ for item in self.order_items: if item.is_subscription: yield item @property def subtotal(self): total = Decimal("0.00") for item in self.order_items: total += item.total return total @property def shipping_total(self): ship_cost = Decimal(0.0) for item in self.order_items: ship_cost = ship_cost + item.shipping_cost return ship_cost @property def total(self): return self.subtotal + self.shipping_total @models.permalink def get_absolute_url(self): return "view_order_detail", (), {"order_number": self.pk} def delete_items(self): """ delete all orderItems for this order """ OrderItem.objects.filter(order=self).delete() class OrderPayment(TimeStampedModel): order = models.OneToOneField(Order) amazon_payment = models.ForeignKey( AmazonFPSResponse, related_name="order_payment", blank=True, null=True ) google_payment = models.ForeignKey( GCNewOrderNotification, related_name="order_payment", blank=True, null=True ) @property def is_amazon(self): if self.amazon_payment: return True return False @property def is_google(self): if self.google_payment: return True return False @property def shipping_state(self): if self.is_google: return self.google_payment.fulfillment_order_state return "N/A" @property def payment_state(self): if self.is_google: return self.google_payment.financial_order_state return "N/A" class OrderItemGiftDetail(TimeStampedModel): 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, choices=STATE_CHOICES) phone = models.CharField(max_length=30) country = models.CharField(max_length=30, choices=COUNTRIES) 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, choices=constants.BILL_CHOICES, default=constants.CHOOSE ) gift_card_delivery = models.CharField( max_length=10, choices=constants.GIFT_CARD_DELIVERY_CHOICES, default=constants.GIFT_CARD_NONE, ) message = models.CharField(max_length=72, null=True, blank=True) class OrderItem(TimeStampedModel): """ store each Product instance purchased in each order """ product = models.ForeignKey(Item) quantity = models.IntegerField(default=1) price = models.DecimalField(max_digits=9, decimal_places=2) order = models.ForeignKey(Order, related_name="items") gift_detail = models.OneToOneField(OrderItemGiftDetail, null=True, blank=True) account_number = models.CharField(max_length=7, null=True, blank=True) @property def is_gift(self): if self.gift_detail: return True return False @property def is_subscription(self): if self.product.is_subscription: return True return False @property def total(self): return self.quantity * self.price @property def name(self): return self.product.title @property def long_description(self): return self.product.long_description @property def sku(self): return self.product.sku def __unicode__(self): return self.product.title + " (" + self.product.sku + ")" @property def 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 if self.quantity == 0: return 0.0 if self.quantity == 1: return initial_cost elif self.quantity > 1: return initial_cost + ( (self.quantity - 1) * self.product.shipping_cost_multiple ) @property def total_plus_shipping(self): return self.total + self.shipping_cost