diff --git a/inventory/admin/item.py b/inventory/admin/item.py index cfb3027..7b2284d 100644 --- a/inventory/admin/item.py +++ b/inventory/admin/item.py @@ -3,7 +3,7 @@ from django.shortcuts import redirect from django.contrib import admin from django.conf import settings -from inventory.models import Item, Documentation +from inventory.models import Item, Documentation, Settings class DocumentationAdmin(admin.ModelAdmin): @@ -19,6 +19,12 @@ class ItemAdmin(admin.ModelAdmin): readonly_fields = ['created_at', 'changed_at'] filter_horizontal = ('tags', 'documentation') + def get_exclude(self, request, obj=None): + s = Settings.objects.first() + if (s.track_amount): + return self.exclude + return (self.exclude or tuple()) + ('count', 'low_count') + def view_on_site(self, obj): url = reverse('item-detail', kwargs={'pk': obj.id}) return settings.SERVER_URL + url diff --git a/inventory/migrations/0006_item_count_item_low_count.py b/inventory/migrations/0006_item_count_item_low_count.py new file mode 100644 index 0000000..9577ad5 --- /dev/null +++ b/inventory/migrations/0006_item_count_item_low_count.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.4 on 2025-01-07 17:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0005_alter_sorting_collation'), + ] + + operations = [ + migrations.AddField( + model_name='item', + name='count', + field=models.PositiveIntegerField(default=1, help_text='Number of parts available'), + ), + migrations.AddField( + model_name='item', + name='low_count', + field=models.PositiveIntegerField(default=0, help_text='Low watermark on which to alert ordering more'), + ), + ] diff --git a/inventory/migrations/0007_settings_track_amount.py b/inventory/migrations/0007_settings_track_amount.py new file mode 100644 index 0000000..47a7f24 --- /dev/null +++ b/inventory/migrations/0007_settings_track_amount.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-01-07 17:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0006_item_count_item_low_count'), + ] + + operations = [ + migrations.AddField( + model_name='settings', + name='track_amount', + field=models.BooleanField(default=False, help_text='Show item count in overview and warn on low watermarks'), + ), + ] diff --git a/inventory/models/item.py b/inventory/models/item.py index 5d4029f..676223f 100644 --- a/inventory/models/item.py +++ b/inventory/models/item.py @@ -16,9 +16,17 @@ class Item(CanBeContained): documentation = models.ManyToManyField('inventory.Documentation', related_name='items', blank=True) tags = models.ManyToManyField('inventory.Tag', blank=True) - metadata = models.JSONField('Custom metadata, used by templates', blank=True, null=True) - created_at = models.DateTimeField(auto_now_add=True) - changed_at = models.DateTimeField(auto_now=True) + count = models.PositiveIntegerField( + default=1, + null=False, + help_text="Number of parts available" + ) + low_count = models.PositiveIntegerField( + default=0, + null=False, + help_text="Low watermark on which to alert ordering more" + ) + def __str__(self): items = [self.name, self.description] @@ -32,6 +40,10 @@ class Item(CanBeContained): return list(self.tags.all()) + list(self.form_factor.tags.all()) else: return list(self.tags.all()) - + + @property + def value(self): + return self.count * self.price + class Meta: ordering = ("name", ) diff --git a/inventory/models/settings.py b/inventory/models/settings.py index a4950f2..71b066b 100644 --- a/inventory/models/settings.py +++ b/inventory/models/settings.py @@ -8,7 +8,16 @@ class Settings(models.Model): default=None, null=True, blank=True, - help_text='Default container to display when calling the index page' + ) + track_amount = models.BooleanField( + default=False, + help_text="Show item count in overview and warn on low watermarks" + ) + currency = models.CharField(max_length=30, help_text="Currency name", default="Euro") + currency_symbol = models.CharField(max_length=20, default="€") + currency_symbol_position = models.BooleanField( + default=True, + help_text="Currency symbol after amount" ) def __str__(self): diff --git a/inventory/static/inventory/css/cell.css b/inventory/static/inventory/css/cell.css index 7c912a1..85e3236 100644 --- a/inventory/static/inventory/css/cell.css +++ b/inventory/static/inventory/css/cell.css @@ -89,6 +89,24 @@ td.disabled { opacity: 0.75; } +.cell .stock { + position: absolute; + top: 5px; + left: 5px; + display: inline; + font-size: xx-small; + color: #808080; + line-height: 10px; +} + +.cell .stock .icon { + display: inline-block; + width: 10px; + height: 10px; + margin: 0 2px 0 0; + vertical-align: text-top; +} + .cell .form_factor { position: absolute; display: inline; @@ -153,7 +171,13 @@ td.disabled { top: 3px; right: 7px; } - + + .cell .stock { + font-size: 75%; + top: 3px; + left: 3px; + } + .cell .price { font-size: 75%; bottom: 3px; diff --git a/inventory/static/inventory/css/main.css b/inventory/static/inventory/css/main.css index 2daa36f..88770ff 100644 --- a/inventory/static/inventory/css/main.css +++ b/inventory/static/inventory/css/main.css @@ -26,6 +26,11 @@ table.attribute-list th { border-style: solid; } +table.attribute-list .small { + color: #808080; + font-size: xx-small; +} + table.box { width: 100%; border-collapse: collapse; @@ -158,8 +163,7 @@ img.icon { margin-right: 10px; width: 18px; height: 18px; - position: relative; - top: 2px; + vertical-align: middle; } img.logo { @@ -277,9 +281,6 @@ table.list thead th { padding: 10px; } -table.list tbody tr { -} - table.list tbody td { border-bottom: 1px solid black; padding: 10px; @@ -322,3 +323,16 @@ table.list tbody td { font-weight: normal; color: #808080; } + +div.icon { + width: 18px; + height: 18px; + display: inline-block; + vertical-align: middle; +} + +div.warning-icon { + background-color: #c00000; + -webkit-mask: url(/static/inventory/img/warn.svg) no-repeat center; + mask: url(/static/inventory/img/warn.svg) no-repeat center; +} \ No newline at end of file diff --git a/inventory/static/inventory/img/warn.svg b/inventory/static/inventory/img/warn.svg new file mode 100644 index 0000000..0f40cbc --- /dev/null +++ b/inventory/static/inventory/img/warn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/inventory/templates/inventory/box-ikea-glis.html b/inventory/templates/inventory/box-ikea-glis.html index 2dd489e..cd6e74e 100644 --- a/inventory/templates/inventory/box-ikea-glis.html +++ b/inventory/templates/inventory/box-ikea-glis.html @@ -9,7 +9,7 @@
{% for compartment in layouted.0.0 %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -17,7 +17,7 @@
{% for compartment in layouted.0.1 %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -27,7 +27,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-ikea-samla.html b/inventory/templates/inventory/box-ikea-samla.html index 2ed455b..9cc4a21 100644 --- a/inventory/templates/inventory/box-ikea-samla.html +++ b/inventory/templates/inventory/box-ikea-samla.html @@ -9,7 +9,7 @@
{% for compartment in layouted.0 %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-pollin-sorter.html b/inventory/templates/inventory/box-pollin-sorter.html index 7a7f1f3..388758a 100644 --- a/inventory/templates/inventory/box-pollin-sorter.html +++ b/inventory/templates/inventory/box-pollin-sorter.html @@ -10,7 +10,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -20,7 +20,7 @@
{% for compartment in layouted.1.0 %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -29,7 +29,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -40,7 +40,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-raaco-1240-123.html b/inventory/templates/inventory/box-raaco-1240-123.html index ea49f3b..c5b16b7 100644 --- a/inventory/templates/inventory/box-raaco-1240-123.html +++ b/inventory/templates/inventory/box-raaco-1240-123.html @@ -11,7 +11,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -27,7 +27,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -42,7 +42,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-raaco-616-123.html b/inventory/templates/inventory/box-raaco-616-123.html index 7f70e7a..480cd00 100644 --- a/inventory/templates/inventory/box-raaco-616-123.html +++ b/inventory/templates/inventory/box-raaco-616-123.html @@ -11,7 +11,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -27,7 +27,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -42,7 +42,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-raaco-928-123.html b/inventory/templates/inventory/box-raaco-928-123.html index cb09638..6dce61e 100644 --- a/inventory/templates/inventory/box-raaco-928-123.html +++ b/inventory/templates/inventory/box-raaco-928-123.html @@ -11,7 +11,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -27,7 +27,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -42,7 +42,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-raaco-even.html b/inventory/templates/inventory/box-raaco-even.html index dbae836..6edab75 100644 --- a/inventory/templates/inventory/box-raaco-even.html +++ b/inventory/templates/inventory/box-raaco-even.html @@ -11,7 +11,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-raaco-simple.html b/inventory/templates/inventory/box-raaco-simple.html index 963ef90..8205526 100644 --- a/inventory/templates/inventory/box-raaco-simple.html +++ b/inventory/templates/inventory/box-raaco-simple.html @@ -10,7 +10,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-smd-box-all.html b/inventory/templates/inventory/box-smd-box-all.html index a9125d7..19d0083 100644 --- a/inventory/templates/inventory/box-smd-box-all.html +++ b/inventory/templates/inventory/box-smd-box-all.html @@ -21,7 +21,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-stanley-sorter-1.html b/inventory/templates/inventory/box-stanley-sorter-1.html index b1f763b..2f36888 100644 --- a/inventory/templates/inventory/box-stanley-sorter-1.html +++ b/inventory/templates/inventory/box-stanley-sorter-1.html @@ -10,7 +10,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -21,7 +21,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -32,7 +32,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -45,7 +45,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/box-stanley-sorter-2.html b/inventory/templates/inventory/box-stanley-sorter-2.html index 42cb1ab..16d8750 100644 --- a/inventory/templates/inventory/box-stanley-sorter-2.html +++ b/inventory/templates/inventory/box-stanley-sorter-2.html @@ -10,7 +10,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -21,7 +21,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -32,7 +32,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
@@ -45,7 +45,7 @@
{% for compartment in item %} - {% include "inventory/cell.html" with item=compartment hilight=hilight %} + {% include "inventory/cell.html" with item=compartment hilight=hilight settings=settings %} {% endfor %}
diff --git a/inventory/templates/inventory/cell.html b/inventory/templates/inventory/cell.html index 66434c1..591b3db 100644 --- a/inventory/templates/inventory/cell.html +++ b/inventory/templates/inventory/cell.html @@ -18,6 +18,13 @@ + {% if settings.track_amount %} + {% if item.count <= item.low_count %} +
{{ item.count }}
+ {% else %} +
{{ item.count }}
+ {% endif %} + {% endif %} {% if item.price %}
{{ item.price | floatformat:2 }} €
{% endif %} diff --git a/inventory/templates/inventory/item_detail.html b/inventory/templates/inventory/item_detail.html index 6489b4a..113652f 100644 --- a/inventory/templates/inventory/item_detail.html +++ b/inventory/templates/inventory/item_detail.html @@ -29,6 +29,25 @@ Description {{ item.description }} + {% if settings.track_amount %} + + Amount + +
+ {% csrf_token %} + + + + +
+ Low watermark: {{ item.low_count }} + + + {% endif %} Tags diff --git a/inventory/views/box.py b/inventory/views/box.py index 5f7c7a6..2a20f6f 100644 --- a/inventory/views/box.py +++ b/inventory/views/box.py @@ -4,7 +4,7 @@ from django.utils.decorators import method_decorator from django.views.generic import ListView, DetailView from django.db.models import QuerySet -from inventory.models import Box +from inventory.models import Box, Settings from .utils import CanBeIndexMixin @@ -54,6 +54,7 @@ class BoxView(CanBeIndexMixin, DetailView): context = self.get_context_data(object=self.object) context['layouted'], _ = self.layout(self.object.item_related.all().order_by('index'), self.object.layout.data) context['hilight'] = hilighted + context['settings'] = Settings.objects.first() return self.render_to_response(context) diff --git a/inventory/views/item.py b/inventory/views/item.py index 061154c..02006f4 100644 --- a/inventory/views/item.py +++ b/inventory/views/item.py @@ -1,15 +1,30 @@ from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.views.generic import ListView, DetailView +from django.shortcuts import get_object_or_404 -from inventory.models import Item +from inventory.models import Item, Settings @method_decorator(login_required, name='dispatch') class ItemView(DetailView): context_object_name = 'item' queryset = Item.objects.all().select_related('container', 'container__layout', 'manufacturer', 'distributor').prefetch_related('documentation') + def get_context_data(self, *args, object_list=None, **kwargs): + result = super().get_context_data(*args, object_list=object_list, **kwargs) + result['settings'] = Settings.objects.first() + return result + def post(self, request, pk): + item = get_object_or_404(Item.objects.filter(pk=pk)) + if request.POST.get('dec', None) is not None: + if item.count > 0: + item.count -= 1 + item.save() + if request.POST.get('save', None) is not None: + item.count = request.POST.get('amount', 0) + item.save() + return self.get(request) @method_decorator(login_required, name='dispatch') class ItemListView(ListView):