def test_03_currencyfield_can_override_default(self): cf = CurrencyField(default=Decimal('99.99')) default = cf.get_default() self.assertNotEqual(default, None) self.assertEqual(default, Decimal('99.99'))
def test_01_currencyfield_has_fixed_format(self): cf = CurrencyField(max_digits=2,decimal_places=1) number = cf.format_number(99.99) #number should *not* end up having only one decimal place self.assertEqual(Decimal(number), Decimal('99.99'))
def test_02_currencyfield_has_default(self): cf = CurrencyField() default = cf.get_default() self.assertNotEqual(default, None) self.assertEqual(default, Decimal('0.0'))
class Product(models.Model): ''' A basic product for the shop Most of the already existing fields here should be generic enough to reside on the "base model" and not on an added property ''' __metaclass__ = ProductMetaClass name = models.CharField(max_length=255) slug = models.SlugField() short_description = models.CharField(max_length=255) long_description = models.TextField() active = models.BooleanField(default=False) date_added = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) unit_price = CurrencyField() # The subtype stores the lowest-level classname in the inheritence tree subtype = models.CharField(max_length=255, editable=False) objects = ProductManager() class Meta: app_label = 'shop' def __unicode__(self): return self.name def get_absolute_url(self): return reverse('product_detail', args=[self.slug]) def get_specific(self): ''' This magic method returns this as an instance of the most specific decendant in the inheritence tree. ''' return getattr(self, self.subtype, self) def get_price(self): ''' Return the price for this item (provided for extensibility) ''' return self.unit_price def get_name(self): ''' Return the name of this Product (provided for extensibility) ''' return self.name @classmethod def save_subtype_name(cls, instance, **kwargs): ''' This is called when a subclass of Product is saved. It sets the relation name to the subclass in the "subtype" field of the Product instance. This allows "get_specific()" to always return the specific instance of the subclass, no matter its type. This method is (and should) only called from the pre_save signal set in ProductMetaClass ''' instance.subtype = cls.__name__.lower()
class BaseOrder(models.Model): """ A model representing an Order. An order is the "in process" counterpart of the shopping cart, which holds stuff like the shipping and billing addresses (copied from the User profile) when the Order is first created), list of items, and holds stuff like the status, shipping costs, taxes, etc... """ PROCESSING = 1 # New order, no shipping/payment backend chosen yet PAYMENT = 2 # The user is filling in payment information CONFIRMED = 3 # Chosen shipping/payment backend, processing payment COMPLETED = 4 # Successful payment confirmed by payment backend SHIPPED = 5 # successful order shipped to client CANCELLED = 6 # order has been cancelled STATUS_CODES = ( (PROCESSING, _('Processing')), (PAYMENT, _('Selecting payment')), (CONFIRMED, _('Confirmed')), (COMPLETED, _('Completed')), (SHIPPED, _('Shipped')), (CANCELLED, _('Cancelled')), ) # If the user is null, the order was created with a session user = models.ForeignKey(User, blank=True, null=True, verbose_name=_('User')) status = models.IntegerField(choices=STATUS_CODES, default=PROCESSING, verbose_name=_('Status')) order_subtotal = CurrencyField(verbose_name=_('Order subtotal')) order_total = CurrencyField(verbose_name=_('Order Total')) shipping_address_text = models.TextField(_('Shipping address'), blank=True, null=True) billing_address_text = models.TextField(_('Billing address'), blank=True, null=True) created = models.DateTimeField(auto_now_add=True, verbose_name=_('Created')) modified = models.DateTimeField(auto_now=True, verbose_name=_('Updated')) class Meta(object): abstract = True app_label = 'shop' verbose_name = _('Order') verbose_name_plural = _('Orders') def __unicode__(self): return _('Order ID: %(id)s') % {'id': self.id} def get_absolute_url(self): return reverse('order_detail', kwargs={'pk': self.pk}) def is_paid(self): """Has this order been integrally paid for?""" return self.amount_paid >= self.order_total is_payed = is_paid #Backward compatability, deprecated spelling def is_completed(self): return self.status == self.COMPLETED @property def amount_paid(self): """ The amount paid is the sum of related orderpayments """ from shop.models import OrderPayment sum_ = OrderPayment.objects.filter(order=self).aggregate( sum=Sum('amount')) result = sum_.get('sum') if result is None: result = Decimal(0) return result amount_payed = amount_paid #Backward compatability, deprecated spelling @property def shipping_costs(self): from shop.models import ExtraOrderPriceField sum_ = Decimal('0.0') cost_list = ExtraOrderPriceField.objects.filter(order=self).filter( is_shipping=True) for cost in cost_list: sum_ += cost.value return sum_ def set_billing_address(self, billing_address): """ Process billing_address trying to get as_text method from address and copying. You can override this method to process address more granulary e.g. you can copy address instance and save FK to it in your order class. """ if hasattr(billing_address, 'as_text'): self.billing_address_text = billing_address.as_text() self.save() def set_shipping_address(self, shipping_address): """ Process shipping_address trying to get as_text method from address and copying. You can override this method to process address more granulary e.g. you can copy address instance and save FK to it in your order class. """ if hasattr(shipping_address, 'as_text'): self.shipping_address_text = shipping_address.as_text() self.save()
class BaseOrder(models.Model): """ A model representing an Order. An order is the "in process" counterpart of the shopping cart, which holds stuff like the shipping and billing addresses (copied from the User profile) when the Order is first created), list of items, and holds stuff like the status, shipping costs, taxes, etc... """ PROCESSING = 10 # New order, addresses and shipping/payment methods chosen (user is in the shipping backend) CONFIRMING = 20 # The order is pending confirmation (user is on the confirm view) CONFIRMED = 30 # The order was confirmed (user is in the payment backend) COMPLETED = 40 # Payment backend successfully completed SHIPPED = 50 # The order was shipped to client CANCELED = 60 # The order was canceled CANCELLED = CANCELED # DEPRECATED SPELLING PAYMENT = 30 # DEPRECATED! STATUS_CODES = ( (PROCESSING, _('Processing')), (CONFIRMING, _('Confirming')), (CONFIRMED, _('Confirmed')), (COMPLETED, _('Completed')), (SHIPPED, _('Shipped')), (CANCELED, _('Canceled')), ) # If the user is null, the order was created with a session user = models.ForeignKey(USER_MODEL, blank=True, null=True, verbose_name=_('User')) status = models.IntegerField(choices=STATUS_CODES, default=PROCESSING, verbose_name=_('Status')) order_subtotal = CurrencyField(verbose_name=_('Order subtotal')) order_total = CurrencyField(verbose_name=_('Order Total')) shipping_address_text = models.TextField(_('Shipping address'), blank=True, null=True) billing_address_text = models.TextField(_('Billing address'), blank=True, null=True) created = models.DateTimeField(auto_now_add=True, verbose_name=_('Created')) modified = models.DateTimeField(auto_now=True, verbose_name=_('Updated')) cart_pk = models.PositiveIntegerField(_('Cart primary key'), blank=True, null=True) class Meta(object): abstract = True app_label = 'shop' verbose_name = _('Order') verbose_name_plural = _('Orders') def __unicode__(self): return _('Order ID: %(id)s') % {'id': self.pk} def get_absolute_url(self): return reverse('order_detail', kwargs={'pk': self.pk}) def is_paid(self): """Has this order been integrally paid for?""" return self.amount_paid >= self.order_total is_payed = is_paid #Backward compatability, deprecated spelling def is_completed(self): return self.status == self.COMPLETED def get_status_name(self): return dict(self.STATUS_CODES)[self.status] @property def amount_paid(self): """ The amount paid is the sum of related orderpayments """ from shop.models import OrderPayment sum_ = OrderPayment.objects.filter(order=self).aggregate( sum=Sum('amount')) result = sum_.get('sum') if result is None: result = Decimal(0) return result amount_payed = amount_paid #Backward compatability, deprecated spelling @property def shipping_costs(self): from shop.models import ExtraOrderPriceField sum_ = Decimal('0.0') cost_list = ExtraOrderPriceField.objects.filter(order=self).filter( is_shipping=True) for cost in cost_list: sum_ += cost.value return sum_ @property def short_name(self): """ A short name for the order, to be displayed on the payment processor's website. Should be human-readable, as much as possible """ return "%s-%s" % (self.pk, self.order_total) def set_billing_address(self, billing_address): """ Process billing_address trying to get as_text method from address and copying. You can override this method to process address more granulary e.g. you can copy address instance and save FK to it in your order class. """ if hasattr(billing_address, 'as_text') and callable( billing_address.as_text): self.billing_address_text = billing_address.as_text() self.save() def set_shipping_address(self, shipping_address): """ Process shipping_address trying to get as_text method from address and copying. You can override this method to process address more granulary e.g. you can copy address instance and save FK to it in your order class. """ if hasattr(shipping_address, 'as_text') and callable( shipping_address.as_text): self.shipping_address_text = shipping_address.as_text() self.save()
class Order(models.Model): """ A model representing an Order. An order is the "in process" counterpart of the shopping cart, which holds stuff like the shipping and billing addresses (copied from the User profile) when the Order is first created), list of items, and holds stuff like the status, shipping costs, taxes, etc... """ PROCESSING = 1 CONFIRMED = 2 COMPLETED = 3 STATUS_CODES = ( (PROCESSING, 'Processing'), # User still checking out the contents (CONFIRMED, 'Confirmed'), # Contents are valid, now we can handle payment etc... (COMPLETED, 'Completed'), # Everything is fine, only need to send the products ) # If the user is null, the order was created with a session user = models.ForeignKey(User, blank=True, null=True) status = models.IntegerField(choices=STATUS_CODES, default=PROCESSING) order_subtotal = CurrencyField() order_total = CurrencyField() payment_method = models.CharField(max_length=255, null=True) # Addresses MUST be copied over to the order when it's created, however # the fields must be nullable since sometimes we cannot create the address # fields right away (for instance when the shopper is a guest) shipping_name = models.CharField(max_length=255, null=True) shipping_address = models.CharField(max_length=255, null=True) shipping_address2 = models.CharField(max_length=255, null=True) shipping_zip_code = models.CharField(max_length=20, null=True) shipping_state = models.CharField(max_length=255, null=True) shipping_country = models.CharField(max_length=255, null=True) billing_name = models.CharField(max_length=255, null=True) billing_address = models.CharField(max_length=255, null=True) billing_address2 = models.CharField(max_length=255, null=True) billing_zip_code = models.CharField(max_length=20, null=True) billing_state = models.CharField(max_length=255, null=True) billing_country = models.CharField(max_length=255, null=True) objects = OrderManager() class Meta: app_label = 'shop' def is_payed(self): """Has this order been integrally payed for?""" return self.amount_payed == self.order_total def is_completed(self): return self.status == self.COMPLETED @property def amount_payed(self): """ The amount payed is the sum of related orderpayments """ sum = OrderPayment.objects.filter(order=self).aggregate( sum=Sum('amount')) result = sum.get('sum') if not result: result = Decimal('0') return result @property def shipping_costs(self): sum = Decimal('0.0') cost_list = ExtraOrderPriceField.objects.filter(order=self).filter( is_shipping=True) for cost in cost_list: sum = sum + cost.value return sum
class Order(models.Model): """ A model representing an Order. An order is the "in process" counterpart of the shopping cart, which holds stuff like the shipping and billing addresses (copied from the User profile) when the Order is first created), list of items, and holds stuff like the status, shipping costs, taxes, etc... """ PROCESSING = 1 # New order, no shipping/payment backend chosen yet CONFIRMED = 2 # Chosen shipping/payment backend, processing payment COMPLETED = 3 # Successful payment confirmed by payment backend SHIPPED = 4 # successful order shipped to client CANCELLED = 5 # order has been cancelled STATUS_CODES = ( (PROCESSING, 'Processing'), (CONFIRMED, 'Confirmed'), (COMPLETED, 'Completed'), (SHIPPED, 'Shipped'), (CANCELLED, 'Cancelled'), ) # If the user is null, the order was created with a session user = models.ForeignKey(User, blank=True, null=True) status = models.IntegerField(choices=STATUS_CODES, default=PROCESSING) order_subtotal = CurrencyField() order_total = CurrencyField() payment_method = models.CharField(max_length=255, null=True) # Addresses MUST be copied over to the order when it's created, however # the fields must be nullable since sometimes we cannot create the address # fields right away (for instance when the shopper is a guest) shipping_name = models.CharField(max_length=255, null=True) shipping_address = models.CharField(max_length=255, null=True) shipping_address2 = models.CharField(max_length=255, null=True) shipping_city = models.CharField(max_length=255, null=True) shipping_zip_code = models.CharField(max_length=20, null=True) shipping_state = models.CharField(max_length=255, null=True) shipping_country = models.CharField(max_length=255, null=True) billing_name = models.CharField(max_length=255, null=True) billing_address = models.CharField(max_length=255, null=True) billing_address2 = models.CharField(max_length=255, null=True) billing_city = models.CharField(max_length=255, null=True) billing_zip_code = models.CharField(max_length=20, null=True) billing_state = models.CharField(max_length=255, null=True) billing_country = models.CharField(max_length=255, null=True) created = models.DateTimeField(auto_now_add=True, verbose_name=_('Created')) modified = models.DateTimeField(auto_now=True, verbose_name=_('Updated')) objects = OrderManager() class Meta: app_label = 'shop' def is_payed(self): """Has this order been integrally payed for?""" return self.amount_payed == self.order_total def is_completed(self): return self.status == self.COMPLETED @property def amount_payed(self): """ The amount payed is the sum of related orderpayments """ sum = OrderPayment.objects.filter(order=self).aggregate( sum=Sum('amount')) result = sum.get('sum') if not result: result = Decimal('0') return result @property def shipping_costs(self): sum = Decimal('0.0') cost_list = ExtraOrderPriceField.objects.filter(order=self).filter( is_shipping=True) for cost in cost_list: sum = sum + cost.value return sum def __unicode__(self): return _('Order ID: %(id)s') % {'id': self.id} def get_absolute_url(self): return reverse('order_detail', kwargs={'pk': self.pk})
def test_01_currencyfield_has_fixed_format(self): cf = CurrencyField(max_digits=2, decimal_places=10) number = cf.format_number(99.99) #number should *not* end up having only one decimal place self.assertEqual(Decimal(number), Decimal('99.99'))
class BaseProduct(models.Model): unit_price = CurrencyField()