From a8021c92eaf21e08da784762ec5695622f74f25a Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 27 Jul 2012 00:14:34 +0200 Subject: add inventory/ --- inventory/__init__.py | 0 inventory/admin.py | 54 +++++++++++ inventory/filters.py | 105 ++++++++++++++++++++++ inventory/models.py | 160 +++++++++++++++++++++++++++++++++ inventory/templatetags/__init__.py | 0 inventory/templatetags/graph_extras.py | 8 ++ inventory/tests.py | 16 ++++ inventory/views.py | 73 +++++++++++++++ 8 files changed, 416 insertions(+) create mode 100644 inventory/__init__.py create mode 100644 inventory/admin.py create mode 100644 inventory/filters.py create mode 100644 inventory/models.py create mode 100644 inventory/templatetags/__init__.py create mode 100644 inventory/templatetags/graph_extras.py create mode 100644 inventory/tests.py create mode 100644 inventory/views.py diff --git a/inventory/__init__.py b/inventory/__init__.py new file mode 100644 index 0000000..e69de29 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: Money in Cent.")) + 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 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 -- cgit v1.2.3