Permalink
Browse files

Adding store stock models and template tag

  • Loading branch information...
1 parent 331d19a commit c496187755443ceed6589ea4326bbf345edb784b Moose committed Dec 6, 2012
View
@@ -1,10 +1,9 @@
.PHONY: sandbox geoip
geoip:
- cd sandbox/geoip
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
- cd -
+ mv GeoLiteCity.dat sandbox/geoip
sandbox:
rm sandbox/sandbox/sandbox.sqlite3 || true
View
@@ -11,6 +11,7 @@ Contents:
.. toctree::
:maxdepth: 2
+ settings
Indices and tables
View
@@ -0,0 +1,9 @@
+Settings
+========
+
+STORES_SRID
+-----------
+
+Default: ``4326`` (i.e. WGS 84)
+
+This sets the SRID for the stores location field.
View
@@ -72,6 +72,7 @@ def configure():
},
GEOIP_PATH = 'sandbox/geoip',
NOSE_ARGS=['-s', '-x', '--with-spec'],
+ STORES_SRID=32140, # Flat projection so spatialite can do distances
**OSCAR_SETTINGS
)
Binary file not shown.
View
Binary file not shown.
View
@@ -3,6 +3,10 @@
from stores import models
-admin.site.register(models.Store)
+class StoreAdmin(admin.ModelAdmin):
+ prepopulated_fields = {"slug": ("name",)}
+
+admin.site.register(models.Store, StoreAdmin)
admin.site.register(models.StoreGroup)
admin.site.register(models.OpeningPeriod)
+admin.site.register(models.StoreStock)
View
@@ -1,3 +1,4 @@
+from django.db import models
from django.contrib.gis.db.models import GeoManager
from django.contrib.gis.db.models.query import GeoQuerySet
@@ -14,5 +15,4 @@ def get_query_set(self):
return StoreQuerySet(self.model)
def pickup_stores(self):
- return self.get_query_set().pickup_stores()
-
+ return self.get_query_set().pickup_stores()

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -3,11 +3,15 @@
from django.utils.translation import ugettext as _
from django.template.defaultfilters import slugify
from django.contrib.gis.db.models import PointField
+from django.contrib.gis.db.models import GeoManager
+from django.conf import settings
+
from oscar.apps.address.abstract_models import AbstractAddress
from stores.managers import StoreManager
+STORES_SRID = getattr(settings, 'STORES_SRID', 4326)
class StoreAddress(AbstractAddress):
store = models.OneToOneField(
@@ -64,7 +68,7 @@ class Store(models.Model):
blank=True, null=True
)
- location = PointField(_("Location"), null=True, blank=True)
+ location = PointField(_("Location"), null=True, blank=True, srid=STORES_SRID)
group = models.ForeignKey('stores.StoreGroup', related_name='stores',
name=_("Group"), null=True, blank=True)
@@ -127,3 +131,37 @@ class Meta:
ordering = ['weekday']
verbose_name = _("Opening period")
verbose_name_plural = _("Opening periods")
+
+
+class StoreStock(models.Model):
+
+ store = models.ForeignKey('stores.Store',
+ related_name='stock')
+ product = models.ForeignKey('catalogue.Product', related_name="store_stock")
+
+ # Stock level information
+ num_in_stock = models.PositiveIntegerField(_("Number in stock"), default=0, blank=True, null=True)
+
+ # The amount of stock allocated in store but not fed back to the master
+ num_allocated = models.IntegerField(_("Number allocated"), default=0, blank=True, null=True)
+
+ location = models.CharField(_("In store location"), max_length=50, blank=True, null=True)
+
+ # Date information
+ date_created = models.DateTimeField(_("Date Created"), auto_now_add=True)
+ date_updated = models.DateTimeField(_("Date Updated"), auto_now=True, db_index=True)
+
+ class Meta:
+ verbose_name = _("Store Stock Record")
+ verbose_name_plural = _("Store Stock Records")
+
+ objects = GeoManager()
+
+ def __unicode__(self):
+ if self.store and self.product:
+ return "%s @ %s" % (self.product.title, self.store.name)
+ return "Store Stock"
+
+ @property
+ def is_available_to_buy(self):
+ return self.num_in_stock > self.num_allocated
No changes.
@@ -0,0 +1,15 @@
+from django import template
+from django.db.models import get_model
+
+StoreStock = get_model('stores', 'StoreStock')
+
+register = template.Library()
+
+@register.assignment_tag
+def store_stock_for_product(product, location=None, limit=20):
+ query_set = StoreStock.objects.filter(product=product)
+ if location:
+ query_set = query_set.distance(location, field_name='store__location').order_by('distance')
+ else:
+ query_set = query_set.order_by('store__name')
+ return query_set[0:limit]
View
@@ -4,4 +4,4 @@ def get_current_ip(request):
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
- return ip
+ return ip
@@ -0,0 +1,62 @@
+from django.test import TestCase
+from django.contrib.gis.geos.point import Point
+from django.template import Template, Context
+from django_dynamic_fixture import get as G
+
+from django.db.models import get_model
+
+Product = get_model('catalogue', 'Product')
+Store = get_model('stores', 'Store')
+StoreStock = get_model('stores', 'StoreStock')
+
+
+class StoreStockTest(TestCase):
+
+ def setUp(self):
+ self.product = G(Product)
+ self.store1_location = '{"type": "Point", "coordinates": [87.39,12.02]}'
+ self.store2_location = '{"type": "Point", "coordinates": [88.39,11.02]}'
+ self.store1 = G(Store, is_pickup_store=True, location=self.store1_location)
+ self.store2 = G(Store, is_pickup_store=True, location=self.store2_location)
+ self.store_stock1 = G(StoreStock, store=self.store1, product=self.product)
+ self.store_stock1 = G(StoreStock, store=self.store2, product=self.product)
+
+ def test_store_stock_loads(self):
+ rendered = Template(
+ '{% load store_stock %}'
+ ).render(Context())
+
+ def test_store_stock_for_product_returns_stock_lines(self):
+ rendered = Template(
+ """
+ {% load store_stock %} {% store_stock_for_product product as store_stock %}
+ {% for stock in store_stock %} {{ stock.store.name }} {% endfor %}
+ """
+ ).render(Context({
+ 'product': self.product
+ }))
+ self.assertTrue(self.store1.name in rendered)
+ self.assertTrue(self.store2.name in rendered)
+
+ def test_store_stock_for_product_limits_when_asked(self):
+ rendered = Template(
+ """
+ {% load store_stock %} {% store_stock_for_product product limit=1 as store_stock %}
+ {% for stock in store_stock %} {{ stock.store.name }} {% endfor %}
+ """
+ ).render(Context({
+ 'product': self.product
+ }))
+ self.assertTrue(self.store1.name in rendered)
+
+ def test_store_stock_for_product_order_by_closed(self):
+ rendered = Template(
+ """
+ {% load store_stock %} {% store_stock_for_product product location=loc as store_stock %}
+ {% for stock in store_stock %}{{ stock.store.name }}{% endfor %}
+ """
+ ).render(Context({
+ 'product': self.product,
+ 'loc': '{"type": "Point", "coordinates": [88.39,11.02]}'
+ }))
+ self.assertTrue("%s%s" % (self.store2.name, self.store1.name) in rendered)

0 comments on commit c496187

Please sign in to comment.