mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-03 22:55:43 +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