From e55a3127714928a175dc65bc9d0cc44bd03bf83b Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Sun, 7 Oct 2018 13:09:07 +0200 Subject: [PATCH 1/6] added location admin, updated readme with features and todos --- README.md | 36 +++++++++++++++++-- inventory/admin.py | 15 ++++++-- .../migrations/0017_auto_20181007_1108.py | 26 ++++++++++++++ inventory/models.py | 18 ++++++---- inventory/templates/inventory/base.html | 2 +- .../templates/inventory/shoppinglist.html | 2 +- 6 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 inventory/migrations/0017_auto_20181007_1108.py diff --git a/README.md b/README.md index a7e6606..308b5eb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,17 @@ Pantry inventory management # Inventory management system written in django - python The object of this django app is to keep track of which goods you own, when they will expire, when you should consume them and when you shoud buy more. +## features +- Enter items in your pantry (or other locations, with their location) with their expiry date +- Items can have a minimum quantity you always want to keep in the pantry + - a shopping list is automatically populated with items whose quantity is below this minimum quantity +- You get an overview of items per expiry date so you know what to consume first (or throw away) + +- Extensive search and filtering and grouping on locations, categories, units, expiry date using the auto generated django admin + interface +- Locations are recursive so things can be in the kitchen pantry closet on the 3rd shelf on the right and still be in + the kitchen + # Getting started `pip3 install django` @@ -29,18 +40,39 @@ The object of this django app is to keep track of which goods you own, when they # feature requests ## High - make expirations a calendar view, generate ics file to import -- add locations to items - public wishlist - one off shoping list +- easy clearing of shopping list - add easy consume view - save date consumed in history +# medium high +- mobile app + - (requires rest api?) + # medium +- make work offline +- add users + - federated? use sqrl instead of passwords? + +# medium low +- allow for lending stuff out + - auto mailings when things should be returned? + - double bookkeeping of where things are if both parties have this set up + - ipfs (+ blockchain?) + - will be done in a seperate app, oos for inventory + - make it look something like this https://getbootstrap.com/docs/4.0/examples/dashboard/ -- easy clearing of shopping list + +- figure out average usage of items over time and predict how much to buy in shopping list based on average expiry + dates +- figure out how long a certain item can last given current stock and average usage + +- easily deploy somewhere (docker? on synology?) ## low - add recepies - shopping list created based on recepy ingredients - auto proposal of recepy based on next expiry dates +- offer to buy things that have been on shopping list for a while online (in bulk/aggregated) diff --git a/inventory/admin.py b/inventory/admin.py index 6175bcf..54a7747 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -8,6 +8,11 @@ class PantryItemInLine(admin.TabularInline): extra = 1 + +class LocationInLine(admin.TabularInline): + model = Location + extra = 1 + def upper_case_name(obj): return obj.name.upper() upper_case_name.short_description = 'Name' @@ -18,7 +23,7 @@ def capitalize_name(obj): upper_case_name.short_description = 'Name' -class PantryItemInLineAdmin(admin.ModelAdmin): +class PantryItemLineAdmin(admin.ModelAdmin): list_filter = ['expiry_date', 'pantry_item__unit', 'pantry_item', 'pantry_item__min_quantity'] search_fields = ['info', 'pantry_item__name', 'pantry_item__info'] autocomplete_fields = ['pantry_item'] @@ -47,6 +52,10 @@ class AutocompleteAdmin(admin.ModelAdmin): search_fields = ["name"] +class LocationAdmin(AutocompleteAdmin): + inlines = [LocationInLine] + + class PantryItemAdmin(admin.ModelAdmin): list_filter = ['category', 'unit', 'min_quantity', 'location'] search_fields = ['info', 'name', 'category__name', 'unit__name'] @@ -73,7 +82,7 @@ class PantryItemAdmin(admin.ModelAdmin): ) admin.site.register(PantryItem, PantryItemAdmin) -admin.site.register(PantryItemLine, PantryItemInLineAdmin) +admin.site.register(PantryItemLine, PantryItemLineAdmin) admin.site.register(Unit, AutocompleteAdmin) admin.site.register(Category, AutocompleteAdmin) -admin.site.register(Location, AutocompleteAdmin) +admin.site.register(Location, LocationAdmin) diff --git a/inventory/migrations/0017_auto_20181007_1108.py b/inventory/migrations/0017_auto_20181007_1108.py new file mode 100644 index 0000000..e77a445 --- /dev/null +++ b/inventory/migrations/0017_auto_20181007_1108.py @@ -0,0 +1,26 @@ +# Generated by Django 2.1.2 on 2018-10-07 11:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0016_auto_20180930_1409'), + ] + + operations = [ + migrations.CreateModel( + name='ShoppingListItem', + fields=[ + ('pantryitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='inventory.PantryItem')), + ], + bases=('inventory.pantryitem',), + ), + migrations.AlterField( + model_name='pantryitem', + name='location', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.Location'), + ), + ] diff --git a/inventory/models.py b/inventory/models.py index c4e48f8..99e3db1 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -46,26 +46,32 @@ class Location(models.Model): return self.name + ' ' + str(self.in_location) return self.name + class PantryItem(models.Model): """A think you keep in your pantry """ - name = models.CharField(max_length=200) category = models.ForeignKey(Category, on_delete=models.PROTECT) min_quantity = models.IntegerField(default=1) #, decimal_places=3, max_digits=32) - unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True) - info = models.CharField(max_length=200, null=True, blank=True) # some things don't have a fixed expiry date, like legumes or garlic, we can specify a default expiration for # this. # if expiry duration is set the expiration date for a pantryitemline will be set to now + duration on save # represents days expiry_duration = models.IntegerField(null=True, blank=True) - # location is saved on a per pantryitem base, not pantryitemline + name = models.CharField(max_length=200) + unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True) + info = models.CharField(max_length=200, null=True, blank=True) + # location is saved on a per item base, not itemline # you can have multiple pantries with subpantries - # if a pantryitem moves to the kitchen or fridge it is no longer a pantry item - location = models.ForeignKey(Location, on_delete=models.PROTECT, null=True) + location = models.ForeignKey(Location, on_delete=models.PROTECT, null=True, blank=True) def __str__(self): return self.name + +class ShoppingListItem(PantryItem): + """Items to buy now that aren't meant for the pantry but for imidiate usage""" + pass + + class PantryItemLine(models.Model): # user? pantry_item = models.ForeignKey(PantryItem, on_delete=models.PROTECT) diff --git a/inventory/templates/inventory/base.html b/inventory/templates/inventory/base.html index e292c21..77542bd 100644 --- a/inventory/templates/inventory/base.html +++ b/inventory/templates/inventory/base.html @@ -21,7 +21,7 @@ Consume
  • {{ pi|title }} (We have {{ pi.total_quantity }} {{pi.unit}} but we want at least - {{ pi.min_quantity }} {{pi.unit }}) + {{ pi.min_quantity }} {{pi.unit }} in {{ pi.location}})
  • {% endfor %} From 2ea523b97ad53896f91ab083f9dfd0026471a8a1 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Fri, 12 Oct 2018 08:29:27 +0200 Subject: [PATCH 2/6] added shoppinglist items for one of things in the shopping list --- inventory/admin.py | 13 +++++++++++++ .../migrations/0018_auto_20181009_1032.py | 19 +++++++++++++++++++ inventory/models.py | 5 +++-- .../templates/inventory/shoppinglist.html | 4 +++- requirements.txt | 3 +++ 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 inventory/migrations/0018_auto_20181009_1032.py create mode 100644 requirements.txt diff --git a/inventory/admin.py b/inventory/admin.py index 54a7747..b0d62c7 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from .models import PantryItem, PantryItemLine, Unit, Category, Location +from .models import ShoppingListItem class PantryItemInLine(admin.TabularInline): @@ -13,6 +14,7 @@ class LocationInLine(admin.TabularInline): model = Location extra = 1 + def upper_case_name(obj): return obj.name.upper() upper_case_name.short_description = 'Name' @@ -81,7 +83,18 @@ class PantryItemAdmin(admin.ModelAdmin): 'info', ) + +class ShoppingListItemAdmin(PantryItemAdmin): + + inlines = [] + fields = ( + 'name', + ('min_quantity', 'unit'), + 'info', + ) + admin.site.register(PantryItem, PantryItemAdmin) +admin.site.register(ShoppingListItem, ShoppingListItemAdmin) admin.site.register(PantryItemLine, PantryItemLineAdmin) admin.site.register(Unit, AutocompleteAdmin) admin.site.register(Category, AutocompleteAdmin) diff --git a/inventory/migrations/0018_auto_20181009_1032.py b/inventory/migrations/0018_auto_20181009_1032.py new file mode 100644 index 0000000..8a1a934 --- /dev/null +++ b/inventory/migrations/0018_auto_20181009_1032.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.2 on 2018-10-09 10:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0017_auto_20181007_1108'), + ] + + operations = [ + migrations.AlterField( + model_name='pantryitem', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.Category'), + ), + ] diff --git a/inventory/models.py b/inventory/models.py index 99e3db1..88ab969 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.urls import reverse class Category(models.Model): @@ -49,8 +50,8 @@ class Location(models.Model): class PantryItem(models.Model): """A think you keep in your pantry """ - category = models.ForeignKey(Category, on_delete=models.PROTECT) - min_quantity = models.IntegerField(default=1) #, decimal_places=3, max_digits=32) + category = models.ForeignKey(Category, on_delete=models.PROTECT, null=True, blank=True) + min_quantity = models.IntegerField(default=1) # some things don't have a fixed expiry date, like legumes or garlic, we can specify a default expiration for # this. # if expiry duration is set the expiration date for a pantryitemline will be set to now + duration on save diff --git a/inventory/templates/inventory/shoppinglist.html b/inventory/templates/inventory/shoppinglist.html index 7df125f..5a605ed 100644 --- a/inventory/templates/inventory/shoppinglist.html +++ b/inventory/templates/inventory/shoppinglist.html @@ -7,8 +7,10 @@
  • {{ pi|title }} (We have {{ pi.total_quantity }} {{pi.unit}} but we want at least - {{ pi.min_quantity }} {{pi.unit }} in {{ pi.location}}) + {{ pi.min_quantity }} {{pi.unit }} in {{ pi.location}} ({{pi.info}}))
  • {% endfor %} + + Add one off item to shoppinglist {% endblock %} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..430b4f9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +#requirements.txt +Django==2.1 +gunicorn From 818d4e9a3867734acf4158e5c52f8029d69d9db3 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Fri, 12 Oct 2018 08:31:09 +0200 Subject: [PATCH 3/6] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 308b5eb..8117e4c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ The object of this django app is to keep track of which goods you own, when they - Enter items in your pantry (or other locations, with their location) with their expiry date - Items can have a minimum quantity you always want to keep in the pantry - a shopping list is automatically populated with items whose quantity is below this minimum quantity + - you can add one off items to this shopping list that are not tracked in the inventory. - You get an overview of items per expiry date so you know what to consume first (or throw away) - Extensive search and filtering and grouping on locations, categories, units, expiry date using the auto generated django admin @@ -41,7 +42,6 @@ The object of this django app is to keep track of which goods you own, when they ## High - make expirations a calendar view, generate ics file to import - public wishlist -- one off shoping list - easy clearing of shopping list - add easy consume view - save date consumed in history From b08f8ef47f5c876c79411997a4afaa6d1ba1884b Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Fri, 12 Oct 2018 09:32:01 +0200 Subject: [PATCH 4/6] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 430b4f9..4f80239 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ #requirements.txt -Django==2.1 +Django>=2.1, < 2.2 gunicorn From 0ae280704d832e81a90d9e813be89276fc733901 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Fri, 12 Oct 2018 09:33:02 +0200 Subject: [PATCH 5/6] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4f80239..339cfc9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ #requirements.txt -Django>=2.1, < 2.2 +Django>=2.1.2, < 2.2 gunicorn From 712186709fcd1d801dc2b65ccbd1f04481e4f2a8 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Fri, 12 Oct 2018 22:01:47 +0200 Subject: [PATCH 6/6] made search work --- inventory/templates/inventory/base.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inventory/templates/inventory/base.html b/inventory/templates/inventory/base.html index 77542bd..9b90a58 100644 --- a/inventory/templates/inventory/base.html +++ b/inventory/templates/inventory/base.html @@ -49,8 +49,8 @@ Disabled -
    - + +