diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index 3012cdc61f..2817664908 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -900,7 +900,7 @@ PLUGINS_ENABLED = _is_true(get_setting(
PLUGIN_FILE = get_plugin_file()
# Plugin Directories (local plugins will be loaded from these directories)
-PLUGIN_DIRS = ['plugin.builtin', 'barcodes.plugins', ]
+PLUGIN_DIRS = ['plugin.builtin', ]
if not TESTING:
# load local deploy directory in prod
diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py
index 2b31d7c3b5..d408bd7346 100644
--- a/InvenTree/InvenTree/urls.py
+++ b/InvenTree/InvenTree/urls.py
@@ -18,7 +18,6 @@ from build.urls import build_urls
from order.urls import order_urls
from plugin.urls import get_plugin_urls
-from barcodes.api import barcode_api_urls
from common.api import common_api_urls, settings_api_urls
from part.api import part_api_urls, bom_api_urls
from company.api import company_api_urls
@@ -28,6 +27,7 @@ from order.api import order_api_urls
from label.api import label_api_urls
from report.api import report_api_urls
from plugin.api import plugin_api_urls
+from plugin.barcode import barcode_api_urls
from django.conf import settings
from django.conf.urls.static import static
@@ -59,7 +59,6 @@ if settings.PLUGINS_ENABLED:
)
apipatterns += [
- re_path(r'^barcode/', include(barcode_api_urls)),
re_path(r'^settings/', include(settings_api_urls)),
re_path(r'^part/', include(part_api_urls)),
re_path(r'^bom/', include(bom_api_urls)),
@@ -75,6 +74,7 @@ apipatterns += [
# Plugin endpoints
re_path(r'^action/', ActionPluginView.as_view(), name='api-action-plugin'),
+ re_path(r'^barcode/', include(barcode_api_urls)),
# Webhook enpoint
path('', include(common_api_urls)),
diff --git a/InvenTree/barcodes/barcode.py b/InvenTree/barcodes/barcode.py
deleted file mode 100644
index 030552c866..0000000000
--- a/InvenTree/barcodes/barcode.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-import warnings
-
-import plugin.builtin.barcode.mixins as mixin
-import plugin.integration
-
-
-hash_barcode = mixin.hash_barcode
-
-
-class BarcodePlugin(mixin.BarcodeMixin, plugin.integration.IntegrationPluginBase):
- """
- Legacy barcode plugin definition - will be replaced
- Please use the new Integration Plugin API and the BarcodeMixin
- """
- # TODO @matmair remove this with InvenTree 0.7.0
- def __init__(self, barcode_data=None):
- warnings.warn("using the BarcodePlugin is depreceated", DeprecationWarning)
- super().__init__()
- self.init(barcode_data)
diff --git a/InvenTree/barcodes/plugins/digikey_barcode.py b/InvenTree/barcodes/plugins/digikey_barcode.py
deleted file mode 100644
index 656cdfa6f4..0000000000
--- a/InvenTree/barcodes/plugins/digikey_barcode.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-DigiKey barcode decoding
-"""
-
-from barcodes.barcode import BarcodePlugin
-
-
-class DigikeyBarcodePlugin(BarcodePlugin):
-
- PLUGIN_NAME = "DigikeyBarcode"
-
- def validate(self):
- """
- TODO: Validation of Digikey barcodes.
- """
-
- return False
diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py
index 318f4af984..633907f330 100644
--- a/InvenTree/label/apps.py
+++ b/InvenTree/label/apps.py
@@ -265,6 +265,13 @@ class LabelConfig(AppConfig):
'width': 70,
'height': 24,
},
+ {
+ 'file': 'part_label_code128.html',
+ 'name': 'Barcode Part Label',
+ 'description': 'Simple part label with Code128 barcode',
+ 'width': 70,
+ 'height': 24,
+ },
]
for label in labels:
diff --git a/InvenTree/label/templates/label/part/part_label_code128.html b/InvenTree/label/templates/label/part/part_label_code128.html
new file mode 100644
index 0000000000..7f8ef144ec
--- /dev/null
+++ b/InvenTree/label/templates/label/part/part_label_code128.html
@@ -0,0 +1,33 @@
+{% extends "label/label_base.html" %}
+
+{% load barcode %}
+
+{% block style %}
+
+.qr {
+ position: fixed;
+ left: 0mm;
+ top: 0mm;
+ height: {{ height }}mm;
+ width: {{ height }}mm;
+}
+
+.part {
+ font-family: Arial, Helvetica, sans-serif;
+ display: inline;
+ position: absolute;
+ left: {{ height }}mm;
+ top: 2mm;
+}
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
+ {{ part.full_name }}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py
index 1e7e7994ae..53724a36fc 100644
--- a/InvenTree/label/tests.py
+++ b/InvenTree/label/tests.py
@@ -5,20 +5,29 @@ from __future__ import unicode_literals
import os
-from django.test import TestCase
from django.conf import settings
from django.apps import apps
+from django.urls import reverse
from django.core.exceptions import ValidationError
from InvenTree.helpers import validateFilterString
+from InvenTree.api_tester import InvenTreeAPITestCase
-from .models import StockItemLabel, StockLocationLabel
+from .models import StockItemLabel, StockLocationLabel, PartLabel
from stock.models import StockItem
-class LabelTest(TestCase):
+class LabelTest(InvenTreeAPITestCase):
+
+ fixtures = [
+ 'category',
+ 'part',
+ 'location',
+ 'stock'
+ ]
def setUp(self) -> None:
+ super().setUp()
# ensure the labels were created
apps.get_app_config('label').create_labels()
@@ -77,3 +86,13 @@ class LabelTest(TestCase):
with self.assertRaises(ValidationError):
validateFilterString(bad_filter_string, model=StockItem)
+
+ def test_label_rendering(self):
+ """Test label rendering"""
+
+ labels = PartLabel.objects.all()
+ part = PartLabel.objects.first()
+
+ for label in labels:
+ url = reverse('api-part-label-print', kwargs={'pk': label.pk})
+ self.get(f'{url}?parts={part.pk}', expected_code=200)
diff --git a/InvenTree/barcodes/api.py b/InvenTree/plugin/barcode.py
similarity index 97%
rename from InvenTree/barcodes/api.py
rename to InvenTree/plugin/barcode.py
index f36e4b1703..98b111f073 100644
--- a/InvenTree/barcodes/api.py
+++ b/InvenTree/plugin/barcode.py
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
-
-from django.urls import reverse
-from django.urls import path, re_path
+from django.urls import reverse, path, re_path
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ValidationError
@@ -12,8 +10,8 @@ from rest_framework.views import APIView
from stock.models import StockItem
from stock.serializers import StockItemSerializer
-from barcodes.plugins.inventree_barcode import InvenTreeBarcodePlugin
-from barcodes.barcode import hash_barcode
+from plugin.builtin.barcodes.inventree_barcode import InvenTreeBarcodePlugin
+from plugin.builtin.barcodes.mixins import hash_barcode
from plugin import registry
diff --git a/InvenTree/plugin/builtin/barcode/__init__.py b/InvenTree/plugin/builtin/barcode/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/InvenTree/barcodes/__init__.py b/InvenTree/plugin/builtin/barcodes/__init__.py
similarity index 100%
rename from InvenTree/barcodes/__init__.py
rename to InvenTree/plugin/builtin/barcodes/__init__.py
diff --git a/InvenTree/barcodes/plugins/inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/inventree_barcode.py
similarity index 96%
rename from InvenTree/barcodes/plugins/inventree_barcode.py
rename to InvenTree/plugin/builtin/barcodes/inventree_barcode.py
index 604936c216..939bf12c08 100644
--- a/InvenTree/barcodes/plugins/inventree_barcode.py
+++ b/InvenTree/plugin/builtin/barcodes/inventree_barcode.py
@@ -13,7 +13,8 @@ references model objects actually exist in the database.
import json
-from barcodes.barcode import BarcodePlugin
+from plugin import IntegrationPluginBase
+from plugin.mixins import BarcodeMixin
from stock.models import StockItem, StockLocation
from part.models import Part
@@ -21,7 +22,7 @@ from part.models import Part
from rest_framework.exceptions import ValidationError
-class InvenTreeBarcodePlugin(BarcodePlugin):
+class InvenTreeBarcodePlugin(BarcodeMixin, IntegrationPluginBase):
PLUGIN_NAME = "InvenTreeBarcode"
diff --git a/InvenTree/plugin/builtin/barcode/mixins.py b/InvenTree/plugin/builtin/barcodes/mixins.py
similarity index 100%
rename from InvenTree/plugin/builtin/barcode/mixins.py
rename to InvenTree/plugin/builtin/barcodes/mixins.py
diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py
new file mode 100644
index 0000000000..1424d89ff2
--- /dev/null
+++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+"""Unit tests for InvenTreeBarcodePlugin"""
+
+from django.contrib.auth import get_user_model
+from django.urls import reverse
+
+from rest_framework.test import APITestCase
+from rest_framework import status
+
+
+class TestInvenTreeBarcode(APITestCase):
+
+ fixtures = [
+ 'category',
+ 'part',
+ 'location',
+ 'stock'
+ ]
+
+ def setUp(self):
+ # Create a user for auth
+ user = get_user_model()
+ user.objects.create_user('testuser', 'test@testing.com', 'password')
+
+ self.client.login(username='testuser', password='password')
+
+ def test_errors(self):
+ """
+ Test all possible error cases for assigment action
+ """
+
+ def test_assert_error(barcode_data):
+ response = self.client.post(
+ reverse('api-barcode-link'), format='json',
+ data={
+ 'barcode': barcode_data,
+ 'stockitem': 521
+ }
+ )
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertIn('error', response.data)
+
+ # test with already existing stock
+ test_assert_error('{"stockitem": 521}')
+
+ # test with already existing stock location
+ test_assert_error('{"stocklocation": 7}')
+
+ # test with already existing part location
+ test_assert_error('{"part": 10004}')
+
+ # test with hash
+ test_assert_error('{"blbla": 10004}')
+
+ def test_scan(self):
+ """
+ Test that a barcode can be scanned
+ """
+
+ response = self.client.post(reverse('api-barcode-scan'), format='json', data={'barcode': 'blbla=10004'})
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertIn('success', response.data)
diff --git a/InvenTree/plugin/mixins/__init__.py b/InvenTree/plugin/mixins/__init__.py
index fdbe863e19..97d27b48fc 100644
--- a/InvenTree/plugin/mixins/__init__.py
+++ b/InvenTree/plugin/mixins/__init__.py
@@ -7,7 +7,7 @@ from ..builtin.integration.mixins import APICallMixin, AppMixin, LabelPrintingMi
from common.notifications import SingleNotificationMethod, BulkNotificationMethod
from ..builtin.action.mixins import ActionMixin
-from ..builtin.barcode.mixins import BarcodeMixin
+from ..builtin.barcodes.mixins import BarcodeMixin
__all__ = [
'APICallMixin',
diff --git a/InvenTree/barcodes/tests.py b/InvenTree/plugin/test_barcode.py
similarity index 82%
rename from InvenTree/barcodes/tests.py
rename to InvenTree/plugin/test_barcode.py
index b092e7eb32..43a713a57b 100644
--- a/InvenTree/barcodes/tests.py
+++ b/InvenTree/plugin/test_barcode.py
@@ -264,57 +264,3 @@ class BarcodeAPITest(APITestCase):
self.assertIn('error', data)
self.assertNotIn('success', data)
-
-
-class TestInvenTreeBarcode(APITestCase):
-
- fixtures = [
- 'category',
- 'part',
- 'location',
- 'stock'
- ]
-
- def setUp(self):
- # Create a user for auth
- user = get_user_model()
- user.objects.create_user('testuser', 'test@testing.com', 'password')
-
- self.client.login(username='testuser', password='password')
-
- def test_errors(self):
- """
- Test all possible error cases for assigment action
- """
-
- def test_assert_error(barcode_data):
- response = self.client.post(
- reverse('api-barcode-link'), format='json',
- data={
- 'barcode': barcode_data,
- 'stockitem': 521
- }
- )
- self.assertEqual(response.status_code, status.HTTP_200_OK)
- self.assertIn('error', response.data)
-
- # test with already existing stock
- test_assert_error('{"stockitem": 521}')
-
- # test with already existing stock location
- test_assert_error('{"stocklocation": 7}')
-
- # test with already existing part location
- test_assert_error('{"part": 10004}')
-
- # test with hash
- test_assert_error('{"blbla": 10004}')
-
- def test_scan(self):
- """
- Test that a barcode can be scanned
- """
-
- response = self.client.post(reverse('api-barcode-scan'), format='json', data={'barcode': 'blbla=10004'})
- self.assertEqual(response.status_code, status.HTTP_200_OK)
- self.assertIn('success', response.data)