summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2012-07-27 00:14:34 +0200
committerSebastian Reichel <sre@ring0.de>2012-07-27 00:14:34 +0200
commita8021c92eaf21e08da784762ec5695622f74f25a (patch)
tree6909db96a55234032cc0d0bf465bd61d08a2c9a7
parent871d3231ad9655f08e5d0fe9eea265bc11faa1ca (diff)
downloadktt-inventory-system-a8021c92eaf21e08da784762ec5695622f74f25a.tar.bz2
add inventory/
-rw-r--r--inventory/__init__.py0
-rw-r--r--inventory/admin.py54
-rw-r--r--inventory/filters.py105
-rw-r--r--inventory/models.py160
-rw-r--r--inventory/templatetags/__init__.py0
-rw-r--r--inventory/templatetags/graph_extras.py8
-rw-r--r--inventory/tests.py16
-rw-r--r--inventory/views.py73
8 files changed, 416 insertions, 0 deletions
diff --git a/inventory/__init__.py b/inventory/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/inventory/__init__.py
diff --git a/inventory/admin.py b/inventory/admin.py
new file mode 100644
index 0000000..3749578
--- /dev/null
+++ b/inventory/admin.py
@@ -0,0 +1,54 @@
+from django.utils.translation import ugettext_lazy as _
+from django.contrib import admin
+from django.forms.widgets import Select
+from django.db.models import ForeignKey
+import filters
+import models
+
+class BarcodeInline(admin.TabularInline):
+ model = models.Barcode
+ fk_name = "item"
+
+class ItemAdmin(admin.ModelAdmin):
+ formfield_overrides = {
+ ForeignKey: {'widget': Select(attrs = {'class': 'chzn-select'})}
+ }
+
+ list_per_page = 100
+ list_filter = (
+ filters.HasParent,
+ filters.HasBarcode,
+ 'decommissioned',
+ 'tag',
+ )
+ list_display = ('name','category','inUse','parent','barcodes')
+ ordering = ['-id',]
+ search_fields = ['name', 'description', 'barcode__code']
+ filter_horizontal = ('tag',)
+ save_as = True
+ inlines = [ BarcodeInline, ]
+
+class TagAdmin(admin.ModelAdmin):
+ ordering = ['name',]
+ list_filter = (
+ filters.HasIcon,
+ )
+ search_fields = ['name',]
+
+class BarcodeAdmin(admin.ModelAdmin):
+ ordering = ['code',]
+ search_fields = ['code',]
+
+class EliminationAdmin(admin.ModelAdmin):
+ filter_vertical = ('item',)
+
+admin.site.register(models.Item, ItemAdmin)
+admin.site.register(models.Owner)
+admin.site.register(models.AcquisitionType)
+admin.site.register(models.Acquisition)
+admin.site.register(models.Elimination, EliminationAdmin)
+admin.site.register(models.Inventory)
+admin.site.register(models.Tag, TagAdmin)
+admin.site.register(models.BusinessArea)
+admin.site.register(models.Category)
+admin.site.register(models.Barcode, BarcodeAdmin)
diff --git a/inventory/filters.py b/inventory/filters.py
new file mode 100644
index 0000000..74a35dd
--- /dev/null
+++ b/inventory/filters.py
@@ -0,0 +1,105 @@
+from django.utils.translation import ugettext_lazy as _
+from django.contrib.admin import SimpleListFilter
+import models
+
+class HasParent(SimpleListFilter):
+ # Human-readable title which will be displayed in the
+ # right admin sidebar just above the filter options.
+ title = _('has parent')
+
+ # Parameter for the filter that will be used in the URL query.
+ parameter_name = 'has_parent'
+
+ def lookups(self, request, model_admin):
+ """
+ Returns a list of tuples. The first element in each
+ tuple is the coded value for the option that will
+ appear in the URL query. The second element is the
+ human-readable name for the option that will appear
+ in the right sidebar.
+ """
+ return (
+ ('yes', _('Yes')),
+ ('no', _('No')),
+ )
+
+ def queryset(self, request, queryset):
+ """
+ Returns the filtered queryset based on the value
+ provided in the query string and retrievable via
+ `self.value()`.
+ """
+ # Compare the requested value (either 'None' or 'other')
+ # to decide how to filter the queryset.
+ if self.value() == 'yes':
+ return queryset.filter(parent__isnull = False)
+ if self.value() == 'no':
+ return queryset.filter(parent__isnull = True)
+
+class HasBarcode(SimpleListFilter):
+ # Human-readable title which will be displayed in the
+ # right admin sidebar just above the filter options.
+ title = _('has barcode')
+
+ # Parameter for the filter that will be used in the URL query.
+ parameter_name = 'has_barcode'
+
+ def lookups(self, request, model_admin):
+ """
+ Returns a list of tuples. The first element in each
+ tuple is the coded value for the option that will
+ appear in the URL query. The second element is the
+ human-readable name for the option that will appear
+ in the right sidebar.
+ """
+ return (
+ ('yes', _('Yes')),
+ ('no', _('No')),
+ )
+
+ def queryset(self, request, queryset):
+ """
+ Returns the filtered queryset based on the value
+ provided in the query string and retrievable via
+ `self.value()`.
+ """
+ # Compare the requested value (either 'None' or 'other')
+ # to decide how to filter the queryset.
+ if self.value() == 'yes':
+ return queryset.filter(barcode__isnull = False)
+ if self.value() == 'no':
+ return queryset.filter(barcode__isnull = True)
+
+class HasIcon(SimpleListFilter):
+ # Human-readable title which will be displayed in the
+ # right admin sidebar just above the filter options.
+ title = _('has icon')
+
+ # Parameter for the filter that will be used in the URL query.
+ parameter_name = 'has_icon'
+
+ def lookups(self, request, model_admin):
+ """
+ Returns a list of tuples. The first element in each
+ tuple is the coded value for the option that will
+ appear in the URL query. The second element is the
+ human-readable name for the option that will appear
+ in the right sidebar.
+ """
+ return (
+ ('yes', _('Yes')),
+ ('no', _('No')),
+ )
+
+ def queryset(self, request, queryset):
+ """
+ Returns the filtered queryset based on the value
+ provided in the query string and retrievable via
+ `self.value()`.
+ """
+ # Compare the requested value (either 'None' or 'other')
+ # to decide how to filter the queryset.
+ if self.value() == 'yes':
+ return queryset.filter(icon__isnull = False)
+ if self.value() == 'no':
+ return queryset.filter(icon__isnull = True)
diff --git a/inventory/models.py b/inventory/models.py
new file mode 100644
index 0000000..1d8cd67
--- /dev/null
+++ b/inventory/models.py
@@ -0,0 +1,160 @@
+from django.utils.translation import ugettext_lazy as _
+from django.db import models
+
+class Tag(models.Model):
+ name = models.CharField(max_length=64)
+ icon = models.FileField(upload_to="icons/", blank=True, null=True)
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ verbose_name = _("tag")
+ verbose_name_plural = _("tags")
+
+
+class BusinessArea(models.Model):
+ name = models.CharField(max_length=64)
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ verbose_name = _("business area")
+ verbose_name_plural = _("business areas")
+
+class Category(models.Model):
+ name = models.CharField(max_length=64)
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ verbose_name = _("category")
+ verbose_name_plural = _("categories")
+
+
+class AcquisitionType(models.Model):
+ name = models.CharField(max_length=64)
+
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ verbose_name = _("acquisition type")
+ verbose_name_plural = _("acquisition types")
+
+class Owner(models.Model):
+ firstname = models.CharField(max_length=64)
+ lastname = models.CharField(max_length=64)
+
+ def __unicode__(self):
+ return "%s %s" % (self.firstname, self.lastname)
+
+ class Meta:
+ verbose_name = _("owner")
+ verbose_name_plural = _("owners")
+
+class Item(models.Model):
+ name = models.TextField()
+ description = models.TextField(blank=True, verbose_name=_('description'))
+ business_area = models.ForeignKey(BusinessArea, verbose_name=_('business area'))
+ category = models.ForeignKey(Category, verbose_name=_('category'))
+ decommissioned = models.BooleanField(verbose_name=_('decommissioned'))
+ targetQuantity = models.IntegerField(blank=True, null=True, verbose_name=_('target quantity'))
+ depreciation = models.BooleanField(verbose_name=_('deprecation'))
+ datasheet = models.FileField(upload_to="datasheets/", blank=True, null=True, verbose_name=_('datasheet'))
+ parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('parent'), related_name='item_parents')
+ temp_parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('temporal parent'), related_name='item_temp_parents')
+ inUse = models.BooleanField(verbose_name=_('in use'))
+ supplier = models.TextField(blank=True, verbose_name=_('supplier'))
+ note = models.TextField(blank=True, verbose_name=_('note'))
+ ean = models.IntegerField(blank=True, null=True, verbose_name=_('EAN'))
+ premium = models.BooleanField(verbose_name=_('premium'))
+ unlabeled = models.BooleanField(verbose_name=_('unlabeled'))
+ image = models.ImageField(upload_to="images/", blank=True, null=True, verbose_name=_('image'))
+ contact = models.TextField(blank=True, verbose_name=_('contact'))
+ tag = models.ManyToManyField(Tag, verbose_name=_('tags'))
+ permanentLoan = models.BooleanField(verbose_name=_('permanent loan'))
+ owner = models.ForeignKey(Owner, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('owner'))
+
+ def barcodes(self):
+ barcodes = Barcode.objects.filter(item = self.id)
+ result = ', '.join(str(barcode.code) for barcode in barcodes)
+ return result
+ barcodes.short_description = _("barcodes")
+
+ def one_barcode(self):
+ barcodes = Barcode.objects.filter(item = self.id)
+ return barcodes[0].code if barcodes else None
+
+ def has_parent(self):
+ if self.parent is not None:
+ return true
+ return false
+
+ def has_barcode(self):
+ if self.barcodes() != "":
+ return true
+ return false
+
+ def __unicode__(self):
+ return _(u"%(name)s (codes: %(barcodes)s)") % {'name': self.name, 'barcodes': self.barcodes()}
+
+ class Meta:
+ verbose_name = _("item")
+ verbose_name_plural = _("items")
+
+class Barcode(models.Model):
+ code = models.CharField(max_length=10,primary_key=True)
+ item = models.ForeignKey(Item)
+
+ def __unicode__(self):
+ return "%s" % self.code
+
+ def save(self, force_insert=False, force_update=False):
+ self.code = self.code.upper().strip()
+ super(Barcode, self).save(force_insert, force_update)
+
+ class Meta:
+ verbose_name = _("barcode")
+ verbose_name_plural = _("barcodes")
+
+class Acquisition(models.Model):
+ item = models.ForeignKey(Item)
+ date = models.DateField()
+ amount = models.IntegerField()
+ unitPrice = models.IntegerField(blank=True, null=True)
+ kind = models.ForeignKey(AcquisitionType)
+
+ def __unicode__(self):
+ return "%s: %s (%sx)" % (self.date, self.item, self.amount)
+
+ class Meta:
+ verbose_name = _("acquisition")
+ verbose_name_plural = _("acquisitions")
+
+class Elimination(models.Model):
+ item = models.ForeignKey(Item, verbose_name=_("Item"))
+ date = models.DateField(verbose_name=_("Date"))
+ revenue = models.IntegerField(verbose_name=_("Revenue"), help_text=_("Please use the following format: <em>Money in Cent</em>."))
+ reason = models.TextField(verbose_name=_("Reason"))
+
+ def __unicode__(self):
+ return "%s: %s" % (self.date, self.item.__unicode__())
+
+ class Meta:
+ verbose_name = _("elimination")
+ verbose_name_plural = _("eliminations")
+
+class Inventory(models.Model):
+ item = models.ForeignKey(Item)
+ date = models.DateField()
+ amount = models.IntegerField()
+
+ def __unicode__(self):
+ return "%s: %s (%s)" % (str(self.date), str(self.item), str(self.amount))
+
+ class Meta:
+ verbose_name = _("inventory")
+ verbose_name_plural = _("inventory")
diff --git a/inventory/templatetags/__init__.py b/inventory/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/inventory/templatetags/__init__.py
diff --git a/inventory/templatetags/graph_extras.py b/inventory/templatetags/graph_extras.py
new file mode 100644
index 0000000..66788e9
--- /dev/null
+++ b/inventory/templatetags/graph_extras.py
@@ -0,0 +1,8 @@
+from django import template
+from django.template.defaultfilters import stringfilter
+register = template.Library()
+
+@register.filter(name='graphescape')
+@stringfilter
+def graphescape(value):
+ return value.replace('"', '\\"')
diff --git a/inventory/tests.py b/inventory/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/inventory/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
diff --git a/inventory/views.py b/inventory/views.py
new file mode 100644
index 0000000..1ff6ca5
--- /dev/null
+++ b/inventory/views.py
@@ -0,0 +1,73 @@
+from django.shortcuts import get_object_or_404
+from django.utils.translation import ugettext_lazy as _
+from django.shortcuts import render_to_response
+from django.http import HttpResponse
+from django.db.models import Q
+import models
+from django.core.mail import mail_admins
+
+def home(request):
+ return render_to_response('home.html')
+
+def item(request, selectedid):
+ p = get_object_or_404(models.Barcode, pk=selectedid.upper())
+
+ parentpath = []
+ temp_parentpath = []
+
+ x = p.item
+ parentpath.append(x)
+ x = x.parent
+ while x:
+ parentpath.append(x)
+ if x.temp_parent:
+ x = x.temp_parent
+ else:
+ x = x.parent
+
+ x = p.item
+ while x:
+ temp_parentpath.append(x)
+ if x.temp_parent:
+ x = x.temp_parent
+ else:
+ x = x.parent
+
+
+ temp_parentpath.reverse()
+ parentpath.reverse()
+
+ parameters = {
+ "user": request.user,
+ "id": p.item.id,
+ "image": p.item.image,
+ "name": p.item.name,
+ "codes": p.item.barcodes(),
+ "description": p.item.description,
+ "in_use": p.item.inUse,
+ "parent": p.item.parent,
+ "temporary_parent": p.item.temp_parent,
+ "parentpath": parentpath,
+ "temporary_parentpath": temp_parentpath,
+ "children": models.Item.objects.filter(Q(parent = p.item.id) | Q(temp_parent = p.item.id)),
+ "tags": p.item.tag.all(),
+ "owner": p.item.owner,
+
+ }
+ return render_to_response('item.html', parameters)
+
+def search(request, term):
+ results = models.Item.objects.filter(Q(name__contains = term) | Q(description__contains = term))
+
+ return render_to_response('search.html', {
+ "term": term,
+ "results": results
+ })
+
+def graph(request):
+ items = models.Item.objects.all()
+
+ result = render_to_response('graph.txt', {"items": items})
+ result['Content-Type'] = "text/plain; charset=utf-8"
+
+ return result