From 67c675d1a6d66f6f908d3b19cd26f6ef10d38f7e Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Wed, 18 May 2022 13:24:50 +0200 Subject: [PATCH 01/11] Add ManufacturerPartAttachment class --- InvenTree/company/models.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 40afa6db6d..e33580abff 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -22,6 +22,7 @@ from stdimage.models import StdImageField from InvenTree.helpers import getMediaUrl, getBlankImage, getBlankThumbnail from InvenTree.fields import InvenTreeURLField +from InvenTree.models import InvenTreeAttachment from InvenTree.status_codes import PurchaseOrderStatus import InvenTree.validators @@ -380,6 +381,22 @@ class ManufacturerPart(models.Model): return s +class ManufacturerPartAttachment(InvenTreeAttachment): + """ + Model for storing file attachments against a ManufacturerPart object + """ + + @staticmethod + def get_api_url(): + return reverse('api-manufacturer-part-attachment-list') + + def getSubdir(self): + return os.path.join("manufacturer_part_files", str(self.manufacturer_part.id)) + + manufacturer_part = models.ForeignKey(ManufacturerPart, on_delete=models.CASCADE, + verbose_name=_('Manufacturer Part'), related_name='attachments') + + class ManufacturerPartParameter(models.Model): """ A ManufacturerPartParameter represents a key:value parameter for a MnaufacturerPart. From c608778a1b2469f15a9d5183e73fdc549435e66b Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 13:01:45 +0000 Subject: [PATCH 02/11] Add migration --- .../0043_manufacturerpartattachment.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 InvenTree/company/migrations/0043_manufacturerpartattachment.py diff --git a/InvenTree/company/migrations/0043_manufacturerpartattachment.py b/InvenTree/company/migrations/0043_manufacturerpartattachment.py new file mode 100644 index 0000000000..fe526992b0 --- /dev/null +++ b/InvenTree/company/migrations/0043_manufacturerpartattachment.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.13 on 2022-05-01 12:57 + +import InvenTree.fields +import InvenTree.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('company', '0042_supplierpricebreak_updated'), + ] + + operations = [ + migrations.CreateModel( + name='ManufacturerPartAttachment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('attachment', models.FileField(blank=True, help_text='Select file to attach', null=True, upload_to=InvenTree.models.rename_attachment, verbose_name='Attachment')), + ('link', InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external URL', null=True, verbose_name='Link')), + ('comment', models.CharField(blank=True, help_text='File comment', max_length=100, verbose_name='Comment')), + ('upload_date', models.DateField(auto_now_add=True, null=True, verbose_name='upload date')), + ('manufacturer_part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='company.manufacturerpart', verbose_name='Manufacturer Part')), + ('user', models.ForeignKey(blank=True, help_text='User', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User')), + ], + options={ + 'abstract': False, + }, + ), + ] From a373e669cd417c4c2e17746f1fec9597402c2c52 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 13:14:50 +0000 Subject: [PATCH 03/11] Add permission --- InvenTree/users/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py index 7ed689f4a9..3c33614b97 100644 --- a/InvenTree/users/models.py +++ b/InvenTree/users/models.py @@ -101,6 +101,7 @@ class RuleSet(models.Model): 'company_supplierpart', 'company_manufacturerpart', 'company_manufacturerpartparameter', + 'company_manufacturerpartattachment', 'label_partlabel', ], 'stock_location': [ From 3ee32374b48b1ebef25f185d74d557a4239efe5a Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 13:15:37 +0000 Subject: [PATCH 04/11] Add serializer --- InvenTree/company/serializers.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 236dcc15db..54eeb2c191 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -8,6 +8,7 @@ from rest_framework import serializers from sql_util.utils import SubqueryCount +from InvenTree.serializers import InvenTreeAttachmentSerializer from InvenTree.serializers import InvenTreeDecimalField from InvenTree.serializers import InvenTreeImageSerializerField from InvenTree.serializers import InvenTreeModelSerializer @@ -16,7 +17,7 @@ from InvenTree.serializers import InvenTreeMoneySerializer from part.serializers import PartBriefSerializer from .models import Company -from .models import ManufacturerPart, ManufacturerPartParameter +from .models import ManufacturerPart, ManufacturerPartAttachment, ManufacturerPartParameter from .models import SupplierPart, SupplierPriceBreak from common.settings import currency_code_default, currency_code_mappings @@ -142,6 +143,29 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): ] +class ManufacturerPartAttachmentSerializer(InvenTreeAttachmentSerializer): + """ + Serializer for the ManufacturerPartAttachment class + """ + + class Meta: + model = ManufacturerPartAttachment + + fields = [ + 'pk', + 'manufacturer_part', + 'attachment', + 'filename', + 'link', + 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', + ] + + class ManufacturerPartParameterSerializer(InvenTreeModelSerializer): """ Serializer for the ManufacturerPartParameter model From 69ba271bf7ae4b78d01e663adaf495808cc14174 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 13:51:09 +0000 Subject: [PATCH 05/11] Add API endpoints --- InvenTree/company/api.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 146a45f648..c171bf7448 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -12,13 +12,14 @@ from django.urls import include, re_path from django.db.models import Q from InvenTree.helpers import str2bool +from InvenTree.api import AttachmentMixin from .models import Company -from .models import ManufacturerPart, ManufacturerPartParameter +from .models import ManufacturerPart, ManufacturerPartAttachment, ManufacturerPartParameter from .models import SupplierPart, SupplierPriceBreak from .serializers import CompanySerializer -from .serializers import ManufacturerPartSerializer, ManufacturerPartParameterSerializer +from .serializers import ManufacturerPartSerializer, ManufacturerPartAttachmentSerializer, ManufacturerPartParameterSerializer from .serializers import SupplierPartSerializer, SupplierPriceBreakSerializer @@ -160,6 +161,32 @@ class ManufacturerPartDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = ManufacturerPartSerializer +class ManufacturerPartAttachmentList(AttachmentMixin, generics.ListCreateAPIView): + """ + API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload). + """ + + queryset = ManufacturerPartAttachment.objects.all() + serializer_class = ManufacturerPartAttachmentSerializer + + filter_backends = [ + DjangoFilterBackend, + ] + + filter_fields = [ + 'manufacturer_part', + ] + + +class ManufacturerPartAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpooint for ManufacturerPartAttachment model + """ + + queryset = ManufacturerPartAttachment.objects.all() + serializer_class = ManufacturerPartAttachmentSerializer + + class ManufacturerPartParameterList(generics.ListCreateAPIView): """ API endpoint for list view of ManufacturerPartParamater model. From 09a76277888aef563b52a2d26a6c25617515f527 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 13:57:02 +0000 Subject: [PATCH 06/11] Add API URLs --- InvenTree/company/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index c171bf7448..22c5c4b207 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -414,6 +414,12 @@ class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView): manufacturer_part_api_urls = [ + # Base URL for ManufacturerPartAttachment API endpoints + re_path(r'^attachment/', include([ + re_path(r'^(?P\d+)/', ManufacturerPartAttachmentDetail.as_view(), name='api-manufacturer-part-attachment-detail'), + re_path(r'^$', ManufacturerPartAttachmentList.as_view(), name='api-manufacturer-part-attachment-list'), + ])), + re_path(r'^parameter/', include([ re_path(r'^(?P\d+)/', ManufacturerPartParameterDetail.as_view(), name='api-manufacturer-part-parameter-detail'), From fc3e61df24290530b6a1cee67a1148d3573c883d Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 14:03:19 +0000 Subject: [PATCH 07/11] Add sidebar item --- .../company/templates/company/manufacturer_part_sidebar.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InvenTree/company/templates/company/manufacturer_part_sidebar.html b/InvenTree/company/templates/company/manufacturer_part_sidebar.html index bd613f76aa..04f3a39a5b 100644 --- a/InvenTree/company/templates/company/manufacturer_part_sidebar.html +++ b/InvenTree/company/templates/company/manufacturer_part_sidebar.html @@ -4,5 +4,7 @@ {% trans "Parameters" as text %} {% include "sidebar_item.html" with label='parameters' text=text icon="fa-th-list" %} +{% trans "Attachments" as text %} +{% include "sidebar_item.html" with label='attachments' text=text icon="fa-paperclip" %} {% trans "Supplier Parts" as text %} {% include "sidebar_item.html" with label='supplier-parts' text=text icon="fa-building" %} \ No newline at end of file From c6d3cd9bae5070f289eff971376094b89fb0cde4 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 14:12:00 +0000 Subject: [PATCH 08/11] Add content panel --- .../templates/company/manufacturer_part.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index 5a0e741c1a..ae4690f1c6 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -144,6 +144,21 @@ src="{% static 'img/blank_image.png' %}" +
+
+
+

{% trans "Attachments" %}

+ {% include "spacer.html" %} +
+ {% include "attachment_button.html" %} +
+
+
+
+ {% include "attachment_table.html" %} +
+
+
From 72f330ab7553ea43769312ad7bf7a52e95a34b13 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 14:33:44 +0000 Subject: [PATCH 09/11] Add JS --- .../templates/company/manufacturer_part.html | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index ae4690f1c6..a51ea45099 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -193,6 +193,34 @@ src="{% static 'img/blank_image.png' %}" {% block js_ready %} {{ block.super }} +onPanelLoad("attachments", function() { + loadAttachmentTable('{% url "api-manufacturer-part-attachment-list" %}', { + filters: { + manufacturer_part: {{ part.pk }}, + }, + fields: { + manufacturer_part: { + value: {{ part.pk }}, + hidden: true + } + } + }); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-manufacturer-part-attachment-list" %}', + { + data: { + manufacturer_part: {{ part.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); +}); + function reloadParameters() { $("#parameter-table").bootstrapTable("refresh"); } From ed1cc1209e8c47f3dadb31d5381babf6e3117eab Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Sun, 1 May 2022 17:48:55 +0000 Subject: [PATCH 10/11] Add admin class --- InvenTree/company/admin.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/InvenTree/company/admin.py b/InvenTree/company/admin.py index cc672f9ee5..ce5f5945b6 100644 --- a/InvenTree/company/admin.py +++ b/InvenTree/company/admin.py @@ -8,7 +8,7 @@ import import_export.widgets as widgets from .models import Company from .models import SupplierPart from .models import SupplierPriceBreak -from .models import ManufacturerPart, ManufacturerPartParameter +from .models import ManufacturerPart, ManufacturerPartAttachment, ManufacturerPartParameter from part.models import Part @@ -109,6 +109,16 @@ class ManufacturerPartAdmin(ImportExportModelAdmin): autocomplete_fields = ('part', 'manufacturer',) +class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin): + """ + Admin class for ManufacturerPartAttachment model + """ + + list_display = ('manufacturer_part', 'attachment', 'comment') + + autocomplete_fields = ('manufacturer_part',) + + class ManufacturerPartParameterResource(ModelResource): """ Class for managing ManufacturerPartParameter data import/export @@ -175,4 +185,5 @@ admin.site.register(SupplierPart, SupplierPartAdmin) admin.site.register(SupplierPriceBreak, SupplierPriceBreakAdmin) admin.site.register(ManufacturerPart, ManufacturerPartAdmin) +admin.site.register(ManufacturerPartAttachment, ManufacturerPartAttachmentAdmin) admin.site.register(ManufacturerPartParameter, ManufacturerPartParameterAdmin) From 3f67682d53e4f0235acc1054aa67c1b9ca78dd56 Mon Sep 17 00:00:00 2001 From: Jakob Haufe Date: Wed, 18 May 2022 13:22:57 +0200 Subject: [PATCH 11/11] Increment API version --- InvenTree/InvenTree/api_version.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index d2eab15468..e44aedf10b 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -4,11 +4,14 @@ InvenTree API version information # InvenTree API version -INVENTREE_API_VERSION = 49 +INVENTREE_API_VERSION = 50 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v50 -> 2022-05-18 : https://github.com/inventree/InvenTree/pull/2912 + - Implement Attachments for manufacturer parts + v49 -> 2022-05-09 : https://github.com/inventree/InvenTree/pull/2957 - Allows filtering of plugin list by 'active' status - Allows filtering of plugin list by 'mixin' support