From 18c5ad7a6ed250c5b3cd120832369ed7f194e867 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 18:46:39 +1000 Subject: [PATCH 1/9] Add template for collapsible item --- InvenTree/templates/collapse.html | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 InvenTree/templates/collapse.html diff --git a/InvenTree/templates/collapse.html b/InvenTree/templates/collapse.html new file mode 100644 index 0000000000..e1ad9b7917 --- /dev/null +++ b/InvenTree/templates/collapse.html @@ -0,0 +1,21 @@ +
+
+
+
+ + {% block collapse_heading %} + {% endblock %} +
+
+
+
+ {% block collapse_content %} + {% endblock %} +
+
+
+
\ No newline at end of file From fbb120da5338fb737ddfcfdb3b9e6c7a0779d04e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 18:53:03 +1000 Subject: [PATCH 2/9] Use collapse template in allocation page --- InvenTree/build/templates/build/allocate.html | 2 +- .../templates/build/allocation_item.html | 64 +++++++++---------- InvenTree/part/models.py | 6 ++ 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html index c3cda38429..1a8c018e01 100644 --- a/InvenTree/build/templates/build/allocate.html +++ b/InvenTree/build/templates/build/allocate.html @@ -11,7 +11,7 @@
{% for bom_item in bom_items.all %} -{% include "build/allocation_item.html" with item=bom_item build=build %} +{% include "build/allocation_item.html" with item=bom_item build=build collapse_id=bom_item.id %} {% endfor %} diff --git a/InvenTree/build/templates/build/allocation_item.html b/InvenTree/build/templates/build/allocation_item.html index 9982457aca..f9e92a63a8 100644 --- a/InvenTree/build/templates/build/allocation_item.html +++ b/InvenTree/build/templates/build/allocation_item.html @@ -1,38 +1,32 @@ +{% extends "collapse.html" %} + {% load inventree_extras %} -
-
-
-
- -
- Required: -
-
- {% multiply build.quantity item.quantity %} -
-
- Allocated: -
-
- 0 -
-
-
- -
-
-
-
-
-
-
-
- - +{% block collapse_title %} +{{ item.sub_part.name }} +{% endblock %} + +{% block collapse_heading %} +
+ Required:
- \ No newline at end of file +
+ {% multiply build.quantity item.quantity %} +
+
+ Allocated: +
+
+ 0 +
+
+
+ +
+
+{% endblock %} + +{% block collapse_content %} + +
+{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index ab83b584cd..c5e7683427 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -307,6 +307,12 @@ class Part(models.Model): def used_in_count(self): return self.used_in.count() + def required_parts(self): + parts = [] + for bom in self.bom_items.all(): + parts.append(bom.sub_part) + return parts + @property def supplier_count(self): # Return the number of supplier parts available for this part From 4d7ac870e0bed7d62d243b90654185f86ab4ee9f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 19:02:03 +1000 Subject: [PATCH 3/9] Use the collapse template for the stock location list view --- InvenTree/part/templates/part/category.html | 6 +-- .../part/templates/part/subcategories.html | 46 ++++++++----------- InvenTree/stock/templates/stock/location.html | 8 ++-- .../stock/templates/stock/location_list.html | 38 ++++++--------- 4 files changed, 41 insertions(+), 57 deletions(-) diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 3d514389bc..f199cc5981 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -33,9 +33,9 @@ -{% if category %} -{% include "part/subcategories.html" with children=category.children.all %} -{% else %} +{% if category and category.children.all|length > 0 %} +{% include "part/subcategories.html" with children=category.children.all collapse_id="children"%} +{% elif children|length > 0 %} {% include "part/subcategories.html" with children=children %} {% endif %}
diff --git a/InvenTree/part/templates/part/subcategories.html b/InvenTree/part/templates/part/subcategories.html index 5dcfa426ad..abf61d743e 100644 --- a/InvenTree/part/templates/part/subcategories.html +++ b/InvenTree/part/templates/part/subcategories.html @@ -1,27 +1,19 @@ -{% if children|length > 0 %} -
-
-
- -
-
-
    - {% for child in children %} -
  • - {{ child.name }} - {% if child.description %} - - {{ child.description }} - {% endif %} - {{ child.partcount }} -
  • - {% endfor %} -
-
-
-
-
-{% endif %} \ No newline at end of file +{% extends "collapse.html" %} + +{% block collapse_title %} +{{ children | length }} Child Categories +{% endblock %} + +{% block collapse_content %} +
    +{% for child in children %} +
  • + {{ child.name }} + {% if child.description %} + - {{ child.description }} + {% endif %} + {{ child.partcount }} +
  • +{% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 1483d8fc4f..76891ad4cd 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -31,10 +31,10 @@ -{% if location %} -{% include 'stock/location_list.html' with children=location.children.all %} -{% else %} -{% include 'stock/location_list.html' with children=locations %} +{% if location and location.children.all|length > 0 %} +{% include 'stock/location_list.html' with children=location.children.all collapse_id="locations" %} +{% elif locations|length > 0 %} +{% include 'stock/location_list.html' with children=locations collapse_id="locations" %} {% endif %}
diff --git a/InvenTree/stock/templates/stock/location_list.html b/InvenTree/stock/templates/stock/location_list.html index b906133e70..90d01c449c 100644 --- a/InvenTree/stock/templates/stock/location_list.html +++ b/InvenTree/stock/templates/stock/location_list.html @@ -1,23 +1,15 @@ -{% if children|length > 0 %} -
-
-
-
-

- Sub-Locations{{ children|length }} -

-
-
-
-
    - {% for child in children %} -
  • {{ child.name }} - {{ child.description }}
  • - {{ child.partcount }} - - {% endfor %} -
-
-
-
-
-{% endif %} \ No newline at end of file +{% extends "collapse.html" %} + +{% block collapse_title %} +Sub-Locations{{ children|length }} +{% endblock %} + +{% block collapse_content %} +
    +{% for child in children %} +
  • {{ child.name }} - {{ child.description }}
  • + {{ child.partcount }} + +{% endfor %} +
+{% endblock %} \ No newline at end of file From 38100520df00c21e57872d68140ef86adeb8fd42 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:18:34 +1000 Subject: [PATCH 4/9] Add 'to_order' and 'to_build' collapsible panels --- InvenTree/InvenTree/views.py | 17 +++++++++++++++++ InvenTree/build/templates/build/allocate.html | 3 --- InvenTree/part/models.py | 15 +++++++++++++-- InvenTree/templates/InvenTree/index.html | 13 ++++++++++++- .../templates/InvenTree/parts_to_build.html | 14 ++++++++++++++ .../templates/InvenTree/parts_to_order.html | 14 ++++++++++++++ InvenTree/templates/collapse.html | 2 ++ InvenTree/templates/required_part_table.html | 18 ++++++++++++++++++ 8 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 InvenTree/templates/InvenTree/parts_to_build.html create mode 100644 InvenTree/templates/InvenTree/parts_to_order.html create mode 100644 InvenTree/templates/required_part_table.html diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 18267f33c4..9a388c5b2c 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -15,6 +15,8 @@ from django.views import View from django.views.generic import UpdateView, CreateView, DeleteView from django.views.generic.base import TemplateView +from part.models import Part + from rest_framework import views @@ -287,6 +289,21 @@ class IndexView(TemplateView): template_name = 'InvenTree/index.html' + def get_context_data(self, **kwargs): + + context = super(TemplateView, self).get_context_data(**kwargs) + + # Generate a list of orderable parts which have stock below their minimum values + context['to_order'] = [part for part in Part.objects.filter(purchaseable=True) if part.need_to_restock()] + + # Generate a list of buildable parts which have stock below their minimum values + context['to_build'] = [part for part in Part.objects.filter(buildable=True) if part.need_to_restock()] + + print("order:", len(context['to_order'])) + print("build:", len(context['to_build'])) + + return context + class SearchView(TemplateView): """ View for InvenTree search page. diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html index 1a8c018e01..0a3867af8e 100644 --- a/InvenTree/build/templates/build/allocate.html +++ b/InvenTree/build/templates/build/allocate.html @@ -14,9 +14,6 @@ {% include "build/allocation_item.html" with item=bom_item build=build collapse_id=bom_item.id %} {% endfor %} - -
-
diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index c5e7683427..3c321d2b3d 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -193,14 +193,25 @@ class Part(models.Model): def available_stock(self): """ Return the total available stock. - This subtracts stock which is already allocated + + - This subtracts stock which is already allocated to builds """ total = self.total_stock total -= self.allocation_count - return max(total, 0) + return total + + def need_to_restock(self): + """ Return True if this part needs to be restocked + (either by purchasing or building). + + If the allocated_stock exceeds the total_stock, + then we need to restock. + """ + + return (self.total_stock - self.allocation_count) < self.minimum_stock @property def can_build(self): diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index 4150313bf9..91cac4c18c 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -3,9 +3,20 @@ {% block content %}

InvenTree

-

Index!

+{% if to_order %} +{% include "InvenTree/parts_to_order.html" with collapse_id="order" %} +{% endif %} + +{% if to_build %} +{% include "InvenTree/parts_to_build.html" with collapse_id="build" %} +{% endif %} {% endblock %} {% block js_load %} +{{ block.super }} +{% endblock %} + +{% block js_ready %} +{{ block.super }} {% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/InvenTree/parts_to_build.html b/InvenTree/templates/InvenTree/parts_to_build.html new file mode 100644 index 0000000000..e9c1dcdee1 --- /dev/null +++ b/InvenTree/templates/InvenTree/parts_to_build.html @@ -0,0 +1,14 @@ +{% extends "collapse.html" %} +{% block collapse_title %} +Parts to Build{{ to_build | length }} +{% endblock %} + +{% block collapse_heading %} +There are {{ to_build | length }} parts which need building. +{% endblock %} + +{% block collapse_content %} + +{% include "required_part_table.html" with parts=to_build table_id="to-build-table" %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/InvenTree/parts_to_order.html b/InvenTree/templates/InvenTree/parts_to_order.html new file mode 100644 index 0000000000..b68eda7e14 --- /dev/null +++ b/InvenTree/templates/InvenTree/parts_to_order.html @@ -0,0 +1,14 @@ +{% extends "collapse.html" %} +{% block collapse_title %} +Parts to Order{{ to_order | length }} +{% endblock %} + +{% block collapse_heading %} +There are {{ to_order | length }} parts which need to be ordered. +{% endblock %} + +{% block collapse_content %} + +{% include "required_part_table.html" with parts=to_order table_id="to-order-table" %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/collapse.html b/InvenTree/templates/collapse.html index e1ad9b7917..776c9cee35 100644 --- a/InvenTree/templates/collapse.html +++ b/InvenTree/templates/collapse.html @@ -1,3 +1,5 @@ +{% block collapse_preamble %} +{% endblock %}
diff --git a/InvenTree/templates/required_part_table.html b/InvenTree/templates/required_part_table.html new file mode 100644 index 0000000000..4ae1441f11 --- /dev/null +++ b/InvenTree/templates/required_part_table.html @@ -0,0 +1,18 @@ + + + + + + + + + {% for part in parts %} + + + + + + + + {% endfor %} +
PartDescriptionIn StockAllocatedNet Stock
{{ part.name }}{{ part.description }}{{ part.total_stock }}{{ part.allocation_count }}{{ part.available_stock }}
\ No newline at end of file From 194a0962f34a083f3b564235c2006489138d8a67 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:19:08 +1000 Subject: [PATCH 5/9] PEP fixes --- InvenTree/part/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 3c321d2b3d..820df63955 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -207,7 +207,7 @@ class Part(models.Model): """ Return True if this part needs to be restocked (either by purchasing or building). - If the allocated_stock exceeds the total_stock, + If the allocated_stock exceeds the total_stock, then we need to restock. """ From d49ce465e52f366be6309fbc1349acaaad1d5949 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:40:56 +1000 Subject: [PATCH 6/9] Removed UUID field from StockItem - QR code is now created based on a JSON object - This will make it extensible to other things such as StockLocation - Created a helper function to make Barcode objects --- InvenTree/InvenTree/helpers.py | 20 +++++++++++++++++++ .../migrations/0014_auto_20190502_2039.py | 18 +++++++++++++++++ InvenTree/stock/api.py | 1 - .../migrations/0013_remove_stockitem_uuid.py | 17 ++++++++++++++++ InvenTree/stock/models.py | 20 ++++++++++++++++--- InvenTree/stock/serializers.py | 2 -- InvenTree/stock/templates/stock/item.html | 6 +----- 7 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 InvenTree/part/migrations/0014_auto_20190502_2039.py create mode 100644 InvenTree/stock/migrations/0013_remove_stockitem_uuid.py diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 295937af08..c1fee741da 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -3,6 +3,8 @@ Provides helper functions used throughout the InvenTree project """ import io +import json +from datetime import datetime from wsgiref.util import FileWrapper from django.http import StreamingHttpResponse @@ -44,6 +46,24 @@ def WrapWithQuotes(text, quote='"'): return text +def MakeBarcode(object_type, data={}): + """ Generate a string for a barcode. Adds some global InvenTree parameters. + + Args: + data: Python dict obejct which will be rendered to string (must only contain stringable values) + + Returns: + json string of the supplied data plus some other data + """ + + # Add in some generic InvenTree data + data['type'] = object_type + data['tool'] = 'InvenTree' + data['generated'] = str(datetime.now().date()) + + return json.dumps(data, sort_keys=True) + + def DownloadFile(data, filename, content_type='application/text'): """ Create a dynamic file for the user to download. diff --git a/InvenTree/part/migrations/0014_auto_20190502_2039.py b/InvenTree/part/migrations/0014_auto_20190502_2039.py new file mode 100644 index 0000000000..c32c3afe32 --- /dev/null +++ b/InvenTree/part/migrations/0014_auto_20190502_2039.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2 on 2019-05-02 10:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0013_auto_20190429_2229'), + ] + + operations = [ + migrations.AlterField( + model_name='part', + name='URL', + field=models.URLField(blank=True, help_text='Link to extenal URL'), + ), + ] diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 8604f54c8f..a145309cec 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -272,7 +272,6 @@ class StockList(generics.ListCreateAPIView): filter_fields = [ 'part', - 'uuid', 'supplier_part', 'customer', 'belongs_to', diff --git a/InvenTree/stock/migrations/0013_remove_stockitem_uuid.py b/InvenTree/stock/migrations/0013_remove_stockitem_uuid.py new file mode 100644 index 0000000000..79184862ed --- /dev/null +++ b/InvenTree/stock/migrations/0013_remove_stockitem_uuid.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2 on 2019-05-02 10:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0012_auto_20190502_0058'), + ] + + operations = [ + migrations.RemoveField( + model_name='stockitem', + name='uuid', + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index a2ccff16a6..41dc730b41 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -17,7 +17,7 @@ from django.db.models.signals import pre_delete from django.dispatch import receiver from datetime import datetime -import uuid +from InvenTree import helpers from InvenTree.models import InvenTreeTree @@ -126,8 +126,22 @@ class StockItem(models.Model): ('part', 'serial'), ] - # UUID for generating QR codes - uuid = models.UUIDField(default=uuid.uuid4, blank=True, editable=False, help_text='Unique ID for the StockItem') + @property + def format_barcode(self): + """ Return a JSON string for formatting a barcode for this StockItem. + Can be used to perform lookup of a stockitem using barcode + + Contains the following data: + + { type: 'StockItem', stock_id: , part_id: } + + Any other data should be looked up using the InvenTree API (as it may change) + """ + + return helpers.MakeBarcode('StockItem', { + 'stock_id': self.id, + 'part_id': self.part.id + }) # The 'master' copy of the part of which this stock item is an instance part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='locations', help_text='Base part') diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 269e3b4e78..fe8462b16c 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -38,7 +38,6 @@ class StockItemSerializerBrief(serializers.ModelSerializer): model = StockItem fields = [ 'pk', - 'uuid', 'part', 'part_name', 'supplier_part', @@ -65,7 +64,6 @@ class StockItemSerializer(serializers.ModelSerializer): model = StockItem fields = [ 'pk', - 'uuid', 'url', 'part', 'supplier_part', diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index cd2de3bf0d..30b7902886 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -39,10 +39,6 @@ Part {{ item.part.name }} - - UUID - {{ item.uuid }} - {% if item.belongs_to %} Belongs To @@ -114,7 +110,7 @@
- {% qr_from_text item.uuid size="s" image_format="png" error_correction="L" %} + {% qr_from_text item.format_barcode size="s" image_format="png" error_correction="L" %}
From c901294a48cc3f8f1ac780534ee8a18e9c895df2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:50:20 +1000 Subject: [PATCH 7/9] Add more information to the Barcode - API endpoint URL - Add barcode generation for StockLocation --- InvenTree/InvenTree/helpers.py | 7 +++-- InvenTree/stock/api.py | 4 +-- InvenTree/stock/models.py | 28 +++++++++++++++---- InvenTree/stock/templates/stock/location.html | 2 ++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index c1fee741da..f86a61e80d 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -46,11 +46,13 @@ def WrapWithQuotes(text, quote='"'): return text -def MakeBarcode(object_type, data={}): +def MakeBarcode(object_type, object_url, data={}): """ Generate a string for a barcode. Adds some global InvenTree parameters. Args: - data: Python dict obejct which will be rendered to string (must only contain stringable values) + object_type: string describing the object type e.g. 'StockItem' + object_url: url for JSON API detail view of the object + data: Python dict object containing extra datawhich will be rendered to string (must only contain stringable values) Returns: json string of the supplied data plus some other data @@ -58,6 +60,7 @@ def MakeBarcode(object_type, data={}): # Add in some generic InvenTree data data['type'] = object_type + data['url'] = object_url data['tool'] = 'InvenTree' data['generated'] = str(datetime.now().date()) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index a145309cec..2690207f05 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -345,11 +345,11 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView): stock_endpoints = [ - url(r'^$', StockDetail.as_view(), name='stockitem-detail'), + url(r'^$', StockDetail.as_view(), name='api-stock-detail'), ] location_endpoints = [ - url(r'^$', LocationDetail.as_view(), name='stocklocation-detail'), + url(r'^$', LocationDetail.as_view(), name='api-location-detail'), ] stock_api_urls = [ diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 41dc730b41..e84554b89b 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -36,6 +36,19 @@ class StockLocation(InvenTreeTree): def has_items(self): return self.stock_items.count() > 0 + @property + def format_barcode(self): + """ Return a JSON string for formatting a barcode for this StockLocation object """ + + return helpers.MakeBarcode( + 'StockLocation', + reverse('api-location-detail', kwargs={'pk': self.id}), + { + 'id': self.id, + 'name': self.name, + } + ) + @receiver(pre_delete, sender=StockLocation, dispatch_uid='stocklocation_delete_log') def before_delete_stock_location(sender, instance, using, **kwargs): @@ -135,13 +148,18 @@ class StockItem(models.Model): { type: 'StockItem', stock_id: , part_id: } - Any other data should be looked up using the InvenTree API (as it may change) + Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change) """ - return helpers.MakeBarcode('StockItem', { - 'stock_id': self.id, - 'part_id': self.part.id - }) + return helpers.MakeBarcode( + 'StockItem', + reverse('api-stock-detail', kwargs={'pk': self.id}), + { + 'id': self.id, + 'part_id': self.part.id, + 'part_name': self.part.name + } + ) # The 'master' copy of the part of which this stock item is an instance part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='locations', help_text='Base part') diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 1483d8fc4f..16ba463ee2 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -1,5 +1,6 @@ {% extends "stock/stock_app_base.html" %} {% load static %} +{% load qr_code %} {% block content %} + {% qr_from_text location.format_barcode size="s" image_format="png" error_correction="L" %} {% endif %}
From 5a234a1070c8229d05c599b784eaf8a26471210b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:57:53 +1000 Subject: [PATCH 8/9] Added barcode for Part object --- InvenTree/InvenTree/helpers.py | 3 ++- InvenTree/part/models.py | 11 +++++++++++ InvenTree/part/templates/part/detail.html | 3 +++ InvenTree/stock/models.py | 4 ++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index f86a61e80d..605cc5cfb6 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -46,7 +46,7 @@ def WrapWithQuotes(text, quote='"'): return text -def MakeBarcode(object_type, object_url, data={}): +def MakeBarcode(object_type, object_id, object_url, data={}): """ Generate a string for a barcode. Adds some global InvenTree parameters. Args: @@ -60,6 +60,7 @@ def MakeBarcode(object_type, object_url, data={}): # Add in some generic InvenTree data data['type'] = object_type + data['id'] = object_id data['url'] = object_url data['tool'] = 'InvenTree' data['generated'] = str(datetime.now().date()) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index ab83b584cd..0e59eb67a3 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -21,6 +21,7 @@ from django.core.validators import MinValueValidator from django.db.models.signals import pre_delete from django.dispatch import receiver +from InvenTree import helpers from InvenTree.models import InvenTreeTree from company.models import Company @@ -179,6 +180,16 @@ class Part(models.Model): def __str__(self): return "{n} - {d}".format(n=self.name, d=self.description) + @property + def format_barcode(self): + """ Return a JSON string for formatting a barcode for this Part object """ + + return helpers.MakeBarcode( + "Part", + self.id, + reverse('api-part-detail', kwargs={'pk': self.id}), + ) + class Meta: verbose_name = "Part" verbose_name_plural = "Parts" diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 7b148318c9..f5941a7870 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,5 +1,6 @@ {% extends "part/part_base.html" %} {% load static %} +{% load qr_code %} {% block details %} {% include 'part/tabs.html' with tab='detail' %} @@ -115,6 +116,8 @@ {% endif %} +{% qr_from_text part.format_barcode size="s" image_format="png" error_correction="L" %} + {% endblock %} {% block js_load %} diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index e84554b89b..7cdc45b7bc 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -42,9 +42,9 @@ class StockLocation(InvenTreeTree): return helpers.MakeBarcode( 'StockLocation', + self.id, reverse('api-location-detail', kwargs={'pk': self.id}), { - 'id': self.id, 'name': self.name, } ) @@ -153,9 +153,9 @@ class StockItem(models.Model): return helpers.MakeBarcode( 'StockItem', + self.id, reverse('api-stock-detail', kwargs={'pk': self.id}), { - 'id': self.id, 'part_id': self.part.id, 'part_name': self.part.name } From 9f70fff8139f4edd42f72caf4daf449b778807f8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 2 May 2019 20:58:33 +1000 Subject: [PATCH 9/9] Added docstring --- InvenTree/InvenTree/helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 605cc5cfb6..2843dc4eb8 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -51,6 +51,7 @@ def MakeBarcode(object_type, object_id, object_url, data={}): Args: object_type: string describing the object type e.g. 'StockItem' + object_id: ID (Primary Key) of the object in the database object_url: url for JSON API detail view of the object data: Python dict object containing extra datawhich will be rendered to string (must only contain stringable values)