mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Order barcodes (#4575)
* Add barcode support to external orders - ReturnOrder - PurchaseOrder - SalesOrder * Support scanning for new model types * Integrate UI elements for ReturnOrder * Update PurchaseOrder page * SalesOrder implementation
This commit is contained in:
parent
d6715d94c1
commit
7af2bb4e8c
@ -116,13 +116,7 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<td>{% decimal part.available %}<span class='badge bg-dark rounded-pill float-right'>{% render_date part.availability_updated %}</span></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if part.barcode_hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-barcode'></span></td>
|
||||
<td>{% trans "Barcode Identifier" %}</td>
|
||||
<td {% if part.barcode_data %}title='{{ part.barcode_data }}'{% endif %}>{{ part.barcode_hash }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% include "barcode_data.html" with instance=part %}
|
||||
</table>
|
||||
|
||||
{% endblock details %}
|
||||
|
43
InvenTree/order/migrations/0089_auto_20230404_0030.py
Normal file
43
InvenTree/order/migrations/0089_auto_20230404_0030.py
Normal file
@ -0,0 +1,43 @@
|
||||
# Generated by Django 3.2.18 on 2023-04-04 00:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('order', '0088_auto_20230403_1402'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='purchaseorder',
|
||||
name='barcode_data',
|
||||
field=models.CharField(blank=True, help_text='Third party barcode data', max_length=500, verbose_name='Barcode Data'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='purchaseorder',
|
||||
name='barcode_hash',
|
||||
field=models.CharField(blank=True, help_text='Unique hash of barcode data', max_length=128, verbose_name='Barcode Hash'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='returnorder',
|
||||
name='barcode_data',
|
||||
field=models.CharField(blank=True, help_text='Third party barcode data', max_length=500, verbose_name='Barcode Data'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='returnorder',
|
||||
name='barcode_hash',
|
||||
field=models.CharField(blank=True, help_text='Unique hash of barcode data', max_length=128, verbose_name='Barcode Hash'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='salesorder',
|
||||
name='barcode_data',
|
||||
field=models.CharField(blank=True, help_text='Third party barcode data', max_length=500, verbose_name='Barcode Data'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='salesorder',
|
||||
name='barcode_hash',
|
||||
field=models.CharField(blank=True, help_text='Unique hash of barcode data', max_length=128, verbose_name='Barcode Hash'),
|
||||
),
|
||||
]
|
@ -35,7 +35,8 @@ from InvenTree.exceptions import log_error
|
||||
from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
||||
InvenTreeURLField, RoundingDecimalField)
|
||||
from InvenTree.helpers import decimal2string, getSetting, notify_responsible
|
||||
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
|
||||
from InvenTree.models import (InvenTreeAttachment, InvenTreeBarcodeMixin,
|
||||
ReferenceIndexingMixin)
|
||||
from InvenTree.status_codes import (PurchaseOrderStatus, ReturnOrderLineStatus,
|
||||
ReturnOrderStatus, SalesOrderStatus,
|
||||
StockHistoryCode, StockStatus)
|
||||
@ -130,7 +131,7 @@ class TotalPriceMixin(models.Model):
|
||||
return total
|
||||
|
||||
|
||||
class Order(MetadataMixin, ReferenceIndexingMixin):
|
||||
class Order(InvenTreeBarcodeMixin, MetadataMixin, ReferenceIndexingMixin):
|
||||
"""Abstract model for an order.
|
||||
|
||||
Instances of this class:
|
||||
|
@ -66,6 +66,8 @@ class AbstractOrderSerializer(serializers.Serializer):
|
||||
# Boolean field indicating if this order is overdue (Note: must be annotated)
|
||||
overdue = serializers.BooleanField(required=False, read_only=True)
|
||||
|
||||
barcode_hash = serializers.CharField(read_only=True)
|
||||
|
||||
def validate_reference(self, reference):
|
||||
"""Custom validation for the reference field"""
|
||||
|
||||
@ -101,6 +103,7 @@ class AbstractOrderSerializer(serializers.Serializer):
|
||||
'status',
|
||||
'status_text',
|
||||
'notes',
|
||||
'barcode_hash',
|
||||
'overdue',
|
||||
] + extra_fields
|
||||
|
||||
|
@ -23,6 +23,24 @@
|
||||
{% url 'admin:order_purchaseorder_change' order.pk as url %}
|
||||
{% include "admin_button.html" with url=url %}
|
||||
{% endif %}
|
||||
{% if barcodes %}
|
||||
<!-- Barcode actions menu -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='barcode-options' title='{% trans "Barcode actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
<span class='fas fa-qrcode'></span> <span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' role='menu'>
|
||||
<li><a class='dropdown-item' href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
|
||||
{% if roles.purchase_order.change %}
|
||||
{% if order.barcode_hash %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-unlink'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
|
||||
{% else %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-link'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Printing options -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='print-options' title='{% trans "Print actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
@ -97,6 +115,7 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<td>{% trans "Order Description" %}</td>
|
||||
<td>{{ order.description }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% include "barcode_data.html" with instance=order %}
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Order Status" %}</td>
|
||||
@ -304,5 +323,33 @@ $("#export-order").click(function() {
|
||||
exportOrder('{% url "po-export" order.id %}');
|
||||
});
|
||||
|
||||
{% if barcodes %}
|
||||
<!-- Barcode functionality callbacks -->
|
||||
$('#show-qr-code').click(function() {
|
||||
showQRDialog(
|
||||
'{% trans "Purchase Order QR Code" %}',
|
||||
'{"purchaseorder": {{ order.pk }}}'
|
||||
);
|
||||
});
|
||||
|
||||
{% if roles.purchase_order.change %}
|
||||
$("#barcode-link").click(function() {
|
||||
linkBarcodeDialog(
|
||||
{
|
||||
purchaseorder: {{ order.pk }},
|
||||
},
|
||||
{
|
||||
title: '{% trans "Link Barcode to Purchase Order" %}',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#barcode-unlink").click(function() {
|
||||
unlinkBarcode({
|
||||
purchaseorder: {{ order.pk }},
|
||||
});
|
||||
});
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock js_ready %}
|
||||
|
@ -33,6 +33,24 @@ src="{% static 'img/blank_image.png' %}"
|
||||
{% url 'admin:order_returnorder_change' order.pk as url %}
|
||||
{% include "admin_button.html" with url=url %}
|
||||
{% endif %}
|
||||
{% if barcodes %}
|
||||
<!-- Barcode actions menu -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='barcode-options' title='{% trans "Barcode actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
<span class='fas fa-qrcode'></span> <span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' role='menu'>
|
||||
<li><a class='dropdown-item' href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
|
||||
{% if roles.return_order.change %}
|
||||
{% if order.barcode_hash %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-unlink'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
|
||||
{% else %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-link'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Printing actions -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='print-options' title='{% trans "Print actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
@ -89,6 +107,9 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<td>{% trans "Order Description" %}</td>
|
||||
<td>{{ order.description }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
|
||||
{% include "barcode_data.html" with instance=order %}
|
||||
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Order Status" %}</td>
|
||||
@ -230,6 +251,35 @@ $('#print-order-report').click(function() {
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
{% if barcodes %}
|
||||
<!-- Barcode functionality callbacks -->
|
||||
$('#show-qr-code').click(function() {
|
||||
showQRDialog(
|
||||
'{% trans "Return Order QR Code" %}',
|
||||
'{"returnorder": {{ order.pk }}}'
|
||||
);
|
||||
});
|
||||
|
||||
{% if roles.return_order.change %}
|
||||
$("#barcode-link").click(function() {
|
||||
linkBarcodeDialog(
|
||||
{
|
||||
returnorder: {{ order.pk }},
|
||||
},
|
||||
{
|
||||
title: '{% trans "Link Barcode to Return Order" %}',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#barcode-unlink").click(function() {
|
||||
unlinkBarcode({
|
||||
returnorder: {{ order.pk }},
|
||||
});
|
||||
});
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<!-- TODO: Export order callback -->
|
||||
|
||||
{% endblock js_ready %}
|
||||
|
@ -33,6 +33,24 @@ src="{% static 'img/blank_image.png' %}"
|
||||
{% url 'admin:order_salesorder_change' order.pk as url %}
|
||||
{% include "admin_button.html" with url=url %}
|
||||
{% endif %}
|
||||
{% if barcodes %}
|
||||
<!-- Barcode actions menu -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='barcode-options' title='{% trans "Barcode actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
<span class='fas fa-qrcode'></span> <span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' role='menu'>
|
||||
<li><a class='dropdown-item' href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
|
||||
{% if roles.sales_order.change %}
|
||||
{% if order.barcode_hash %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-unlink'><span class='fas fa-unlink'></span> {% trans "Unlink Barcode" %}</a></li>
|
||||
{% else %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-link'><span class='fas fa-link'></span> {% trans "Link Barcode" %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Printing actions -->
|
||||
<div class='btn-group' role='group'>
|
||||
<button id='print-options' title='{% trans "Print actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
|
||||
@ -94,6 +112,7 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<td>{% trans "Order Description" %}</td>
|
||||
<td>{{ order.description }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% include "barcode_data.html" with instance=order %}
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Order Status" %}</td>
|
||||
@ -279,6 +298,35 @@ $('#print-order-report').click(function() {
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
{% if barcodes %}
|
||||
<!-- Barcode functionality callbacks -->
|
||||
$('#show-qr-code').click(function() {
|
||||
showQRDialog(
|
||||
'{% trans "Sales Order QR Code" %}',
|
||||
'{"salesorder": {{ order.pk }}}'
|
||||
);
|
||||
});
|
||||
|
||||
{% if roles.sales_order.change %}
|
||||
$("#barcode-link").click(function() {
|
||||
linkBarcodeDialog(
|
||||
{
|
||||
salesorder: {{ order.pk }},
|
||||
},
|
||||
{
|
||||
title: '{% trans "Link Barcode to Sales Order" %}',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#barcode-unlink").click(function() {
|
||||
unlinkBarcode({
|
||||
salesorder: {{ order.pk }},
|
||||
});
|
||||
});
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
$('#export-order').click(function() {
|
||||
exportOrder('{% url "so-export" order.id %}');
|
||||
});
|
||||
|
@ -302,13 +302,7 @@
|
||||
<td>{{ part.keywords }}{% include "clip.html"%}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if part.barcode_hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-barcode'></span></td>
|
||||
<td>{% trans "Barcode Identifier" %}</td>
|
||||
<td {% if part.barcode_data %}title='{{ part.barcode_data }}'{% endif %}>{{ part.barcode_hash }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% include "barcode_data.html" with instance=part %}
|
||||
</table>
|
||||
</div>
|
||||
<div class='col-sm-6'>
|
||||
|
@ -11,12 +11,13 @@ import json
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from company.models import SupplierPart
|
||||
import company.models
|
||||
import order.models
|
||||
import part.models
|
||||
import stock.models
|
||||
from InvenTree.helpers import hash_barcode
|
||||
from part.models import Part
|
||||
from plugin import InvenTreePlugin
|
||||
from plugin.mixins import BarcodeMixin
|
||||
from stock.models import StockItem, StockLocation
|
||||
|
||||
|
||||
class InvenTreeInternalBarcodePlugin(BarcodeMixin, InvenTreePlugin):
|
||||
@ -33,10 +34,13 @@ class InvenTreeInternalBarcodePlugin(BarcodeMixin, InvenTreePlugin):
|
||||
"""Returns a list of database models which support barcode functionality"""
|
||||
|
||||
return [
|
||||
Part,
|
||||
StockItem,
|
||||
StockLocation,
|
||||
SupplierPart,
|
||||
company.models.SupplierPart,
|
||||
order.models.PurchaseOrder,
|
||||
order.models.ReturnOrder,
|
||||
order.models.SalesOrder,
|
||||
part.models.Part,
|
||||
stock.models.StockItem,
|
||||
stock.models.StockLocation,
|
||||
]
|
||||
|
||||
def format_matched_response(self, label, model, instance):
|
||||
|
@ -155,13 +155,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% if item.barcode_hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-barcode'></span></td>
|
||||
<td>{% trans "Barcode Identifier" %}</td>
|
||||
<td {% if item.barcode_data %}title='{{ item.barcode_data }}'{% endif %}>{{ item.barcode_hash }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% include "barcode_data.html" with instance=item %}
|
||||
|
||||
{% if item.batch %}
|
||||
<tr>
|
||||
<td><span class='fas fa-layer-group'></span></td>
|
||||
@ -537,6 +532,7 @@ $('#stock-edit-status').click(function () {
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if barcodes %}
|
||||
$("#show-qr-code").click(function() {
|
||||
showQRDialog(
|
||||
'{% trans "Stock Item QR Code" %}',
|
||||
@ -544,7 +540,6 @@ $("#show-qr-code").click(function() {
|
||||
);
|
||||
});
|
||||
|
||||
{% if barcodes %}
|
||||
$("#barcode-link").click(function() {
|
||||
linkBarcodeDialog(
|
||||
{
|
||||
|
@ -150,13 +150,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if location and location.barcode_hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-barcode'></span></td>
|
||||
<td>{% trans "Barcode Identifier" %}</td>
|
||||
<td {% if location.barcode_data %}title='{{ location.barcode_data }}'{% endif %}>{{ location.barcode_hash }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% include "barcode_data.html" with instance=location %}
|
||||
</table>
|
||||
{% endblock details_left %}
|
||||
|
||||
|
10
InvenTree/templates/barcode_data.html
Normal file
10
InvenTree/templates/barcode_data.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% load i18n %}
|
||||
{% if instance and instance.barcode_hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-barcode'></span></td>
|
||||
<td>{% trans "Barcode Identifier" %}</td>
|
||||
<td {% if instance.barcode_data %}title='{{ instance.barcode_data }}'{% endif %}>
|
||||
{{ instance.barcode_hash}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
Loading…
Reference in New Issue
Block a user