Ejemplo n.º 1
0
 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'))
Ejemplo n.º 2
0
 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'))
Ejemplo n.º 3
0
 def test_02_currencyfield_has_default(self):
     cf = CurrencyField()
     default = cf.get_default()
     self.assertNotEqual(default, None)
     self.assertEqual(default, Decimal('0.0'))
Ejemplo n.º 4
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()
Ejemplo n.º 5
0
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()
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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})
Ejemplo n.º 9
0
 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'))
Ejemplo n.º 10
0
 def test_02_currencyfield_has_default(self):
     cf = CurrencyField()
     default = cf.get_default()
     self.assertNotEqual(default, None)
     self.assertEqual(default, Decimal('0.0'))
Ejemplo n.º 11
0
 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'))
Ejemplo n.º 12
0
class BaseProduct(models.Model):
    unit_price = CurrencyField()