class BaseOrderItem(models.Model): """ A line Item for an order. """ order = models.ForeignKey(get_model_string('Order'), related_name='items', verbose_name=_('Order')) product_reference = models.CharField(max_length=255, verbose_name=_('Product reference')) product_name = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('Product name')) product = models.ForeignKey(get_model_string('Product'), verbose_name=_('Product'), null=True, blank=True, **f_kwargs) unit_price = CurrencyField(verbose_name=_('Unit price')) quantity = models.IntegerField(verbose_name=_('Quantity')) line_subtotal = CurrencyField(verbose_name=_('Line subtotal')) line_total = CurrencyField(verbose_name=_('Line total')) class Meta(object): abstract = True app_label = 'shop' verbose_name = _('Order item') verbose_name_plural = _('Order items') def save(self, *args, **kwargs): if not self.product_name and self.product: self.product_name = self.product.get_name() super(BaseOrderItem, self).save(*args, **kwargs)
class BaseCartItem(models.Model): """ This is a holder for the quantity of items in the cart and, obviously, a pointer to the actual Product being purchased :) """ cart = models.ForeignKey(get_model_string('Cart'), related_name="items") quantity = models.IntegerField() product = models.ForeignKey(get_model_string('Product')) class Meta(object): abstract = True app_label = 'shop' verbose_name = _('Cart item') verbose_name_plural = _('Cart items') def __init__(self, *args, **kwargs): # That will hold extra fields to display to the user # (ex. taxes, discount) super(BaseCartItem, self).__init__(*args, **kwargs) self.extra_price_fields = [] # list of tuples (label, value) # These must not be stored, since their components can be changed # between sessions / logins etc... self.line_subtotal = Decimal('0.0') self.line_total = Decimal('0.0') self.current_total = Decimal('0.0') # Used by cart modifiers def get_base_unit_price(self, **kwargs): """ Returns products price (provided for extensibility). """ return self.product.get_price() def get_base_line_subtotal(self, request): """ Returns base line subtotal (product_unit_price * self.quantity) """ return self.get_base_unit_price(request=request) * self.quantity def update(self, request): self.extra_price_fields = [] # Reset the price fields self.line_subtotal = self.get_base_line_subtotal(request) self.current_total = self.line_subtotal for modifier in cart_modifiers_pool.get_modifiers_list(): # We now loop over every registered price modifier, # most of them will simply add a field to extra_payment_fields modifier.process_cart_item(self, request) self.line_total = self.current_total return self.line_total
class CartDiscountCode(models.Model): """ Model holds entered discount code for ``Cart``. """ cart = models.ForeignKey(get_model_string('Cart'), editable=False) code = models.CharField(_('Discount code'), max_length=30) class Meta: verbose_name = _('Cart discount code') verbose_name_plural = _('Cart discount codes')
class ProductOptionGroupsMixin(models.Model): """ A mixin for product definitions with grouped options """ class Meta(object): abstract = True verbose_name = _('Product mixin with options from named groups') options_groups = models.ManyToManyField(get_model_string( 'OptionGroup', namespace='shop_optiongroups'), blank=True, null=True)
class ProductTextOptionsMixin(models.Model): """ A mixin for product definitions with text options """ class Meta(object): abstract = True verbose_name = _('Product mixin with customizable text options') text_options = models.ManyToManyField(get_model_string( 'TextOption', 'shop_textoptions'), blank=True, null=True)
class Price(models.Model): """ A product price """ product = models.ForeignKey(get_model_string('Product')) currency = models.ForeignKey(Currency) price = models.DecimalField(max_digits=12, decimal_places=4) def __unicode__(self): price = self.currency.format(self.price) return u' '.join([self.currency.before, price, self.currency.after]).strip()
class CartDiscountCode(models.Model): """ Model holds entered discount code for ``Cart``. """ cart = models.ForeignKey(get_model_string('Cart'), editable=False) code = models.CharField(_('Discount code'), max_length=30) class Meta: verbose_name = _('Cart discount code') verbose_name_plural = _('Cart discount codes') def clean_fields(self, *args, **kwargs): super(CartDiscountCode, self).clean_fields(*args, **kwargs) if not DiscountBase.objects.active(code=self.code): msg = _('Discount code is invalid or expired.') raise ValidationError({'code': [msg]})