mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 13:05:42 +00:00
Barcode Refactor (#3640)
* define a simple model mixin class for barcode * Adds generic function for assigning a barcode to a model instance * StockItem model now implements the BarcodeMixin class * Implement simple unit tests for new code * Fix unit tests * Data migration for uid field * Remove references to old 'uid' field * Migration for removing old uid field from StockItem model * Bump API version * Change lookup_barcode to be a classmethod * Change barcode_model_type to be a class method * Cleanup for generic barcode scan and assign API: - Raise ValidationError as appropriate - Improved unit testing - Groundwork for future generic implementation * Further unit tests for barcode scanning * Adjust error messages for compatibility * Unit test fix * Fix hash_barcode function - Add unit tests to ensure it produces the same results as before the refactor * Add BarcodeMixin to Part model * Remove old format_barcode function from Part model * Further fixes for unit tests * Add support for assigning arbitrary barcode to Part instance - Simplify barcode API - Add more unit tests * More unit test fixes * Update unit test * Adds generic endpoint for unassigning barcode data * Update web dialog for unlinking a barcode * Template cleanup * Add Barcode mixin to StockLocation class * Add some simple unit tests for new model mixin * Support assigning / unassigning barcodes for StockLocation * remove failing outdated test * Update template to integrate new barcode support for StockLocation * Add BarcodeMixin to SupplierPart model * Adds QR code view for SupplierPart * Major simplification of barcode API endpoints - Separate existing barcode plugin into two separate classes - Simplify and consolidate the response from barcode scanning - Update unit testing * Yet more unit test fixes * Yet yet more unit test fixes
This commit is contained in:
23
InvenTree/part/migrations/0086_auto_20220912_0007.py
Normal file
23
InvenTree/part/migrations/0086_auto_20220912_0007.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2.15 on 2022-09-12 00:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('part', '0085_partparametertemplate_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='part',
|
||||
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='part',
|
||||
name='barcode_hash',
|
||||
field=models.CharField(blank=True, help_text='Unique hash of barcode data', max_length=128, verbose_name='Barcode Hash'),
|
||||
),
|
||||
]
|
@ -43,7 +43,7 @@ from InvenTree import helpers, validators
|
||||
from InvenTree.fields import InvenTreeNotesField, InvenTreeURLField
|
||||
from InvenTree.helpers import decimal2money, decimal2string, normalize
|
||||
from InvenTree.models import (DataImportMixin, InvenTreeAttachment,
|
||||
InvenTreeTree)
|
||||
InvenTreeBarcodeMixin, InvenTreeTree)
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
SalesOrderStatus)
|
||||
from order import models as OrderModels
|
||||
@ -300,7 +300,7 @@ class PartManager(TreeManager):
|
||||
|
||||
|
||||
@cleanup.ignore
|
||||
class Part(MetadataMixin, MPTTModel):
|
||||
class Part(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
|
||||
"""The Part object represents an abstract part, the 'concept' of an actual entity.
|
||||
|
||||
An actual physical instance of a Part is a StockItem which is treated separately.
|
||||
@ -941,18 +941,6 @@ class Part(MetadataMixin, MPTTModel):
|
||||
|
||||
responsible = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, verbose_name=_('Responsible'), related_name='parts_responible')
|
||||
|
||||
def format_barcode(self, **kwargs):
|
||||
"""Return a JSON string for formatting a barcode for this Part object."""
|
||||
return helpers.MakeBarcode(
|
||||
"part",
|
||||
self.id,
|
||||
{
|
||||
"name": self.full_name,
|
||||
"url": reverse('api-part-detail', kwargs={'pk': self.id}),
|
||||
},
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@property
|
||||
def category_path(self):
|
||||
"""Return the category path of this Part instance"""
|
||||
|
@ -45,6 +45,11 @@
|
||||
{% if barcodes %}
|
||||
<li><a class='dropdown-item' href='#' id='show-qr-code'><span class='fas fa-qrcode'></span> {% trans "Show QR Code" %}</a></li>
|
||||
{% endif %}
|
||||
{% if part.barcode_hash %}
|
||||
<li><a class='dropdown-item' href='#' id='barcode-unlink'><span class='fas fa-unlink'></span> {% trans "Unink 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 %}
|
||||
{% if labels_enabled %}
|
||||
<li><a class='dropdown-item' href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li>
|
||||
{% endif %}
|
||||
@ -167,6 +172,7 @@
|
||||
<td>{% trans "Description" %}</td>
|
||||
<td>{{ part.description }}{% include "clip.html"%}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<!-- Part info messages -->
|
||||
@ -295,6 +301,13 @@
|
||||
<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 %}
|
||||
</table>
|
||||
</div>
|
||||
<div class='col-sm-6'>
|
||||
@ -391,6 +404,7 @@
|
||||
}
|
||||
);
|
||||
|
||||
{% if barcodes %}
|
||||
$("#show-qr-code").click(function() {
|
||||
launchModalForm(
|
||||
"{% url 'part-qr' part.id %}",
|
||||
@ -400,6 +414,24 @@
|
||||
);
|
||||
});
|
||||
|
||||
$('#barcode-unlink').click(function() {
|
||||
unlinkBarcode({
|
||||
part: {{ part.pk }},
|
||||
});
|
||||
});
|
||||
|
||||
$('#barcode-link').click(function() {
|
||||
linkBarcodeDialog(
|
||||
{
|
||||
part: {{ part.pk }},
|
||||
},
|
||||
{
|
||||
title: '{% trans "Link Barcode to Part" %}',
|
||||
}
|
||||
);
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
{% if labels_enabled %}
|
||||
$('#print-label').click(function() {
|
||||
printPartLabels([{{ part.pk }}]);
|
||||
|
@ -144,6 +144,15 @@ class PartTest(TestCase):
|
||||
|
||||
Part.objects.rebuild()
|
||||
|
||||
def test_barcode_mixin(self):
|
||||
"""Test the barcode mixin functionality"""
|
||||
|
||||
self.assertEqual(Part.barcode_model_type(), 'part')
|
||||
|
||||
p = Part.objects.get(pk=1)
|
||||
barcode = p.format_barcode(brief=True)
|
||||
self.assertEqual(barcode, '{"part": 1}')
|
||||
|
||||
def test_tree(self):
|
||||
"""Test that the part variant tree is working properly"""
|
||||
chair = Part.objects.get(pk=10000)
|
||||
@ -243,7 +252,7 @@ class PartTest(TestCase):
|
||||
"""Test barcode format functionality"""
|
||||
barcode = self.r1.format_barcode(brief=False)
|
||||
self.assertIn('InvenTree', barcode)
|
||||
self.assertIn(self.r1.name, barcode)
|
||||
self.assertIn('"part": {"id": 3}', barcode)
|
||||
|
||||
def test_copy(self):
|
||||
"""Test that we can 'deep copy' a Part instance"""
|
||||
|
Reference in New Issue
Block a user