Selling tickets or variable inventory items using Satchmo

by Sumit Chachra on September 8, 2010

Satchmo is a popular Django based e-commerce system. Its well suited for the most part to sell things like shirts and shoes that come in various sizes / colors (variations) etc. These are items that a seller would have a certain amount of in stock, and sell out when the inventory hits 0.

There are situations however this doesn’t work as well. Say you’re a bakery that sells cupcakes and macaroons. Lets assume you bake 100 cupcakes and 50 macaroons every day. So thats the max you can sell on a daily basis. Some days you won’t sell all, but the next day you may run out. This means your inventory number is not fixed.

Moreover the way you’ll define your “product” (thing that customer buys) will need to change. Instead of saying that “I sold a cupcake”, you have to say “I sold a cupcake on Sep. 7, 2010″. The temporal aspect is important, since your inventory is not static. The date may represent the order date or a date in the future (say you take pre-orders).

The exact same scenario applies to sellers of theater tickets (or tickets of any kind really), hotel rooms etc. Almost any kind of commerce online that has daily or variable inventory levels and / or perishable items.

OK, so how to go about solving this problem. Without going into too many details, its obvious we need to use what Satchmo calls Custom Product(s). Apart from that we need to capture the core product type (cupcake or macaroon or hotel room) etc. Below you will find a VariableInventoryProductType class that represents a typical type of product and a VariableInventoryProduct class that has a FK to a core Satchmo product, a day and a type of product. This is the product the customer is really buying (executive suite on December 25, 2010… room would be a product type and executive suite would be a “variation” of that).

import logging

from django.conf import settings as django_settings
from django.db import models
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _

from product.models import SHIP_CLASS_CHOICES, Product, OptionGroup, Price
from product.modules.configurable.models import ConfigurableProduct

class VariableInventoryProductType(models.Model):
    """
    Represents a type of product thats sold by the seller. In case of a Theater for example only one instance of
    this would exist. In case of a bakery say, the number of instances would be the same as the number of different
    types of items the bakery sells.
    """
    name = models.CharField(max_length=255)
    description = models.TextField()
    slug = models.CharField(max_length=255, db_index=True)
    image = ImageField()
    default_inventory = models.IntegerField(verbose_name='Default daily inventory')
    active = models.BooleanField(default=True, db_index=True)
    order = models.IntegerField(db_index=True, default=0)
    base_price = models.DecimalField(max_digits=6, decimal_places=2)
    option_group = models.ForeignKey(OptionGroup, blank=True, null=True)
    shipclass = models.CharField(_('Shipping'), choices=SHIP_CLASS_CHOICES, default="YES", max_length=10)
    featured = models.BooleanField(default=False, db_index=True)

    class Meta:
        ordering = ('order', )

    def __unicode__(self):
        return self.name

class VariableInventoryProductManager(models.Manager):
    def get_product(self, product_type, day, create=True):
        qset = self.filter(product_type=product_type, day=day)
        if qset:
            return qset.get()
        elif create:
            logging.info('Creating new product of type: %s and day: %s' % (product_type.name, day))
            # create real satchmo product first.
            product = Product()
            product.site = Site.objects.get_current()
            product.name = '%s on %s' % (product_type.name, day)
            product.items_in_stock = product_type.default_inventory
            product.shipclass = product_type.shipclass
            product.save()

            p = Price()
            p.product = product
            p.price = product_type.base_price
            p.save()

            # Create Variations
            if product_type.option_group:
                configurable_product = ConfigurableProduct(product=product)
                configurable_product.save()
                configurable_product.option_group.add(product_type.option_group)
                configurable_product.create_subs = True
                configurable_product.save()

            return self.create(product=product, product_type=product_type, day=day)
        else:
            return None

class VariableInventoryProduct(models.Model):
    """
    Actual product thats sold by the store. FKed to an actual satchmo product.
    """
    product = models.OneToOneField(Product)
    product_type = models.ForeignKey(VariableInventoryProductType)
    day = models.DateField(db_index=True)

    objects = VariableInventoryProductManager()

    class Meta:
        unique_together = ('product_type', 'day')

    def _get_subtype(self):
        return 'VariableInventoryProduct'

    def __unicode__(self):
        return '%s on %s' % (self.product_type.name, self.day)
    blog comments powered by Disqus

    Previous post:

    Next post:

    Powered by Tivix