class Product models Model Root class for all Products name models Cha

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
class Product(models.Model):
"""
Root class for all Products
"""
name = models.CharField(_("Full Name"), max_length=255)
slug = models.SlugField(_("Slug Name"), unique=True, prepopulate_from=('name',), core=True, blank=False)
short_description = models.TextField(_("Short description of product"), help_text=_("This should be a 1 or 2 line description for use in product listing screens"), max_length=200, default='', blank=True)
description = models.TextField(_("Description of product"), help_text=_("This field can contain HTML and should be a few paragraphs explaining the background of the product, and anything that would help the potential customer make their purchase."), default='', blank=True)
category = models.ManyToManyField(Category, filter_interface=True, blank=True, verbose_name=_("Category"))
items_in_stock = models.IntegerField(_("Number in stock"), default=0)
meta = models.TextField(_("Meta Description"), max_length=200, blank=True, null=True, help_text=_("Meta description for this product"))
date_added = models.DateField(_("Date added"), null=True, blank=True)
active = models.BooleanField(_("Is product active?"), default=True, help_text=_("This will determine whether or not this product will appear on the site"))
is_product = models.BooleanField(_("Is it a product for sell?"), default=True)
featured = models.BooleanField(_("Featured Item"), default=False, help_text=_("Featured items will show on the front page"))
ordering = models.IntegerField(_("Ordering"), default=0, help_text=_("Override alphabetical order in category display"))
weight = models.DecimalField(_("Weight"), max_digits=8, decimal_places=2, null=True, blank=True)
length = models.DecimalField(_("Length"), max_digits=6, decimal_places=2, null=True, blank=True)
width = models.DecimalField(_("Width"), max_digits=6, decimal_places=2, null=True, blank=True)
height = models.DecimalField(_("Height"), max_digits=6, decimal_places=2, null=True, blank=True)
related_items = models.ManyToManyField('self', blank=True, null=True, filter_interface=True, verbose_name=_('Related Items'), related_name='related_products')
also_purchased = models.ManyToManyField('self', blank=True, null=True, verbose_name=_('Previously Purchased'), related_name='also_products')
taxable = models.BooleanField(_("Taxable"), default=False)
taxClass = models.ForeignKey(TaxClass, verbose_name=_('Tax Class'), blank=True, null=True, help_text=_("If it is taxable, what kind of tax?"))
objects = ProductManager()
def _get_mainImage(self):
img = False
if self.productimage_set.count() > 0:
img = self.productimage_set.order_by('sort')[0]
else:
# try to get a main image by looking at the parent if this has one
try:
parent = self.productvariation.parent
img = parent.product.main_image
except ProductVariation.DoesNotExist:
pass
if not img:
#This should be a "Image Not Found" placeholder image
try:
img = ProductImage.objects.filter(product__isnull=True).order_by('sort')[0]
except IndexError:
import sys
print >>sys.stderr, 'Warning: default product image not found - try syncdb'
return img
main_image = property(_get_mainImage)
def _get_fullPrice(self):
"""
returns price as a Decimal
"""
subtype = self.get_subtype_with_attr('unit_price')
price = None
if subtype:
price = subtype.unit_price
else:
price = self._get_qty_price(1)
if not price:
price = Decimal("0.00")
return price
unit_price = property(_get_fullPrice)
def get_qty_price(self, qty):
"""
If QTY_DISCOUNT prices are specified, then return the appropriate discount price for
the specified qty. Otherwise, return the unit_price
returns price as a Decimal
"""
subtype = self.get_subtype_with_attr('get_qty_price')
if subtype:
price = subtype.get_qty_price(qty)
else:
price = self._get_qty_price(qty)
if not price:
price = self._get_fullPrice()
return price
def _get_qty_price(self, qty):
"""
returns price as a Decimal
"""
qty_discounts = self.price_set.exclude(expires__isnull=False, expires__lt=datetime.date.today()).filter(quantity__lte=qty)
if qty_discounts.count() > 0:
# Get the price with the quantity closest to the one specified without going over
return qty_discounts.order_by('-quantity')[0].price
else:
return None
def in_stock(self):
subtype = self.get_subtype_with_attr('in_stock')
if subtype:
return subtype.in_stock
if self.items_in_stock > 0:
return True
else:
return False;
def __unicode__(self):
return self.name
def get_absolute_url(self):
return urlresolvers.reverse('satchmo_product',
kwargs={'product_slug': self.slug})
class Admin:
list_display = ('name', 'unit_price',)
list_filter = ('category',)
fields = (
(None, {'fields': ('category', 'name', 'slug', 'description', 'short_description', 'date_added', 'active', 'is_product', 'featured', 'items_in_stock','ordering')}),
(_('Meta Data'), {'fields': ('meta',), 'classes': 'collapse'}),
(_('Item Dimensions'), {'fields': (('length', 'width','height',),'weight'), 'classes': 'collapse'}),
(_('Tax'), {'fields':('taxable', 'taxClass'), 'classes': 'collapse'}),
(_('Related Products'), {'fields':('related_items','also_purchased'),'classes':'collapse'}),
)
search_fields = ['slug', 'name',]
class Meta:
ordering = ('ordering', 'name',)
order_with_respect_to = 'unit_price'
verbose_name = _("Product")
verbose_name_plural = _("Products")
def save(self):
if not self.id:
self.date_added = datetime.date.today()
super(Product, self).save()
def get_subtypes(self):
types = []
for key in config_value('PRODUCT', 'PRODUCT_TYPES'):
app, subtype = key.split("::")
try:
if getattr(self, subtype.lower()):
types += [subtype]
except models.ObjectDoesNotExist:
pass
return tuple(types)
get_subtypes.short_description = "Product SubTypes"
def get_subtype_with_attr(self, attr):
for type in self.get_subtypes():
subtype = getattr(self, type.lower())
if hasattr(subtype, attr):
return subtype
return None
def _has_variants(self):
subtype = self.get_subtype_with_attr('has_variants')
if subtype:
return subtype.has_variants
return False
has_variants = property(_has_variants)
def _get_category(self):
"""
Return the primary category associated with this product
"""
subtype = self.get_subtype_with_attr('get_category')
if subtype:
return subtype.get_category
return self.category.all()[0].name
get_category = property(_get_category)
def _get_downloadable(self):
"""
If this Product has any subtypes associated with it that are downloadable, then
consider it downloadable
"""
for prod_type in self.get_subtypes():
subtype = getattr(self, prod_type.lower())
if hasattr(subtype, 'is_downloadable'):
return True
return False
is_downloadable = property(_get_downloadable)
def _get_shippable(self):
"""
If this Product has any subtypes associated with it that are not
shippable, then consider the product not shippable.
If it is downloadable, then we don't ship it either.
"""
if self.is_downloadable:
return False
subtype = self.get_subtype_with_attr('is_shippable')
if subtype and not subtype.is_shippable:
return False
return True
is_shippable = property(_get_shippable)