Merge pull request #205 from SchrodingersGat/qr-codes

Qr codes
This commit is contained in:
Oliver 2019-05-02 21:15:34 +10:00 committed by GitHub
commit 6482b54bc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 114 additions and 13 deletions

View File

@ -3,6 +3,8 @@ Provides helper functions used throughout the InvenTree project
""" """
import io import io
import json
from datetime import datetime
from wsgiref.util import FileWrapper from wsgiref.util import FileWrapper
from django.http import StreamingHttpResponse from django.http import StreamingHttpResponse
@ -44,6 +46,29 @@ def WrapWithQuotes(text, quote='"'):
return text return text
def MakeBarcode(object_type, object_id, object_url, data={}):
""" Generate a string for a barcode. Adds some global InvenTree parameters.
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)
Returns:
json string of the supplied data plus some other 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())
return json.dumps(data, sort_keys=True)
def DownloadFile(data, filename, content_type='application/text'): def DownloadFile(data, filename, content_type='application/text'):
""" Create a dynamic file for the user to download. """ Create a dynamic file for the user to download.

View File

@ -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'),
),
]

View File

@ -21,6 +21,7 @@ from django.core.validators import MinValueValidator
from django.db.models.signals import pre_delete from django.db.models.signals import pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from InvenTree import helpers
from InvenTree.models import InvenTreeTree from InvenTree.models import InvenTreeTree
from company.models import Company from company.models import Company
@ -179,6 +180,16 @@ class Part(models.Model):
def __str__(self): def __str__(self):
return "{n} - {d}".format(n=self.name, d=self.description) 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: class Meta:
verbose_name = "Part" verbose_name = "Part"
verbose_name_plural = "Parts" verbose_name_plural = "Parts"

View File

@ -1,5 +1,6 @@
{% extends "part/part_base.html" %} {% extends "part/part_base.html" %}
{% load static %} {% load static %}
{% load qr_code %}
{% block details %} {% block details %}
{% include 'part/tabs.html' with tab='detail' %} {% include 'part/tabs.html' with tab='detail' %}
@ -115,6 +116,8 @@
</div> </div>
{% endif %} {% endif %}
{% qr_from_text part.format_barcode size="s" image_format="png" error_correction="L" %}
{% endblock %} {% endblock %}
{% block js_load %} {% block js_load %}

View File

@ -272,7 +272,6 @@ class StockList(generics.ListCreateAPIView):
filter_fields = [ filter_fields = [
'part', 'part',
'uuid',
'supplier_part', 'supplier_part',
'customer', 'customer',
'belongs_to', 'belongs_to',
@ -346,11 +345,11 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
stock_endpoints = [ stock_endpoints = [
url(r'^$', StockDetail.as_view(), name='stockitem-detail'), url(r'^$', StockDetail.as_view(), name='api-stock-detail'),
] ]
location_endpoints = [ location_endpoints = [
url(r'^$', LocationDetail.as_view(), name='stocklocation-detail'), url(r'^$', LocationDetail.as_view(), name='api-location-detail'),
] ]
stock_api_urls = [ stock_api_urls = [

View File

@ -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',
),
]

View File

@ -17,7 +17,7 @@ from django.db.models.signals import pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from datetime import datetime from datetime import datetime
import uuid from InvenTree import helpers
from InvenTree.models import InvenTreeTree from InvenTree.models import InvenTreeTree
@ -36,6 +36,19 @@ class StockLocation(InvenTreeTree):
def has_items(self): def has_items(self):
return self.stock_items.count() > 0 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',
self.id,
reverse('api-location-detail', kwargs={'pk': self.id}),
{
'name': self.name,
}
)
@receiver(pre_delete, sender=StockLocation, dispatch_uid='stocklocation_delete_log') @receiver(pre_delete, sender=StockLocation, dispatch_uid='stocklocation_delete_log')
def before_delete_stock_location(sender, instance, using, **kwargs): def before_delete_stock_location(sender, instance, using, **kwargs):
@ -126,8 +139,27 @@ class StockItem(models.Model):
('part', 'serial'), ('part', 'serial'),
] ]
# UUID for generating QR codes @property
uuid = models.UUIDField(default=uuid.uuid4, blank=True, editable=False, help_text='Unique ID for the StockItem') 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: <pk>, part_id: <part_pk> }
Voltagile data (e.g. stock quantity) should be looked up using the InvenTree API (as it may change)
"""
return helpers.MakeBarcode(
'StockItem',
self.id,
reverse('api-stock-detail', kwargs={'pk': 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 # 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') part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='locations', help_text='Base part')

View File

@ -38,7 +38,6 @@ class StockItemSerializerBrief(serializers.ModelSerializer):
model = StockItem model = StockItem
fields = [ fields = [
'pk', 'pk',
'uuid',
'part', 'part',
'part_name', 'part_name',
'supplier_part', 'supplier_part',
@ -65,7 +64,6 @@ class StockItemSerializer(serializers.ModelSerializer):
model = StockItem model = StockItem
fields = [ fields = [
'pk', 'pk',
'uuid',
'url', 'url',
'part', 'part',
'supplier_part', 'supplier_part',

View File

@ -39,10 +39,6 @@
<td>Part</td> <td>Part</td>
<td><a href="{% url 'part-stock' item.part.id %}">{{ item.part.name }}</td> <td><a href="{% url 'part-stock' item.part.id %}">{{ item.part.name }}</td>
</tr> </tr>
<tr>
<td>UUID</td>
<td>{{ item.uuid }}</td>
</tr>
{% if item.belongs_to %} {% if item.belongs_to %}
<tr> <tr>
<td>Belongs To</td> <td>Belongs To</td>
@ -114,7 +110,7 @@
</table> </table>
</div> </div>
<div class='col-sm-6'> <div class='col-sm-6'>
{% 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" %}
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
{% extends "stock/stock_app_base.html" %} {% extends "stock/stock_app_base.html" %}
{% load static %} {% load static %}
{% load qr_code %}
{% block content %} {% block content %}
<div class='row'> <div class='row'>
@ -25,6 +26,7 @@
<li><a href="#" id='location-delete' title='Delete stock location'>Delete</a></li> <li><a href="#" id='location-delete' title='Delete stock location'>Delete</a></li>
</ul> </ul>
</div> </div>
{% qr_from_text location.format_barcode size="s" image_format="png" error_correction="L" %}
{% endif %} {% endif %}
</div> </div>
</h3> </h3>