From 87235b7e6f6679b611353f645fc63cc7dd5d0cd7 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Wed, 30 Jun 2021 09:17:28 +1000
Subject: [PATCH] Replace StockItemAttachmentCreate form

- Also replace drag-and-drop
- Add 'hidden' option for form fields
- Adds renderer for StockItem model
---
 InvenTree/stock/serializers.py                |  2 +
 .../templates/stock/item_attachments.html     | 26 +++++++++--
 InvenTree/stock/urls.py                       |  1 -
 InvenTree/stock/views.py                      | 46 -------------------
 InvenTree/templates/js/forms.js               | 24 ++++++++--
 InvenTree/templates/js/model_renderers.js     | 25 ++++++++--
 6 files changed, 66 insertions(+), 58 deletions(-)

diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py
index a0b7e3403a..38301bdd1f 100644
--- a/InvenTree/stock/serializers.py
+++ b/InvenTree/stock/serializers.py
@@ -288,6 +288,8 @@ class StockItemAttachmentSerializer(InvenTreeModelSerializer):
 
     attachment = InvenTreeAttachmentSerializerField(required=True)
 
+    # TODO: Record the uploading user when creating or updating an attachment!
+
     class Meta:
         model = StockItemAttachment
 
diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html
index a022403d02..abd89c57c3 100644
--- a/InvenTree/stock/templates/stock/item_attachments.html
+++ b/InvenTree/stock/templates/stock/item_attachments.html
@@ -21,10 +21,11 @@
 
 enableDragAndDrop(
         '#attachment-dropzone',
-        "{% url 'stock-item-attachment-create' %}",
+        "{% url 'api-stock-attachment-list' %}",
         {
             data: {
                 stock_item: {{ item.id }},
+                user: {{ user.pk }},
             },
             label: 'attachment',
             success: function(data, status, xhr) {
@@ -34,10 +35,27 @@ enableDragAndDrop(
     );
 
 $("#new-attachment").click(function() {
-    launchModalForm("{% url 'stock-item-attachment-create' %}?item={{ item.id }}",
+
+    constructForm(
+        '{% url "api-stock-attachment-list" %}',
         {
-            reload: true, 
-        });
+            method: 'POST',
+            fields: {
+                attachment: {},
+                comment: {},
+                stock_item: {
+                    value: {{ item.pk }},
+                    hidden: true,
+                },
+                user: {
+                    value: {{ user.pk }},
+                    hidden: true,
+                }
+            },
+            reload: true,
+            title: '{% trans "Add Attachment" %}',
+        }
+    );
 });
 
 $("#attachment-table").on('click', '.attachment-edit-button', function() {
diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py
index c0b6341744..01eb6f4704 100644
--- a/InvenTree/stock/urls.py
+++ b/InvenTree/stock/urls.py
@@ -64,7 +64,6 @@ stock_urls = [
 
     # URLs for StockItem attachments
     url(r'^item/attachment/', include([
-        url(r'^new/', views.StockItemAttachmentCreate.as_view(), name='stock-item-attachment-create'),
         url(r'^(?P<pk>\d+)/edit/', views.StockItemAttachmentEdit.as_view(), name='stock-item-attachment-edit'),
         url(r'^(?P<pk>\d+)/delete/', views.StockItemAttachmentDelete.as_view(), name='stock-item-attachment-delete'),
     ])),
diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py
index bc3e8cb462..3608d5d553 100644
--- a/InvenTree/stock/views.py
+++ b/InvenTree/stock/views.py
@@ -255,52 +255,6 @@ class StockLocationQRCode(QRCodeView):
             return None
 
 
-class StockItemAttachmentCreate(AjaxCreateView):
-    """
-    View for adding a new attachment for a StockItem
-    """
-
-    model = StockItemAttachment
-    form_class = StockForms.EditStockItemAttachmentForm
-    ajax_form_title = _("Add Stock Item Attachment")
-    ajax_template_name = "modal_form.html"
-
-    def save(self, form, **kwargs):
-        """ Record the user that uploaded the attachment """
-
-        attachment = form.save(commit=False)
-        attachment.user = self.request.user
-        attachment.save()
-
-    def get_data(self):
-        return {
-            'success': _("Added attachment")
-        }
-
-    def get_initial(self):
-        """
-        Get initial data for the new StockItem attachment object.
-
-        - Client must provide a valid StockItem ID
-        """
-
-        initials = super().get_initial()
-
-        try:
-            initials['stock_item'] = StockItem.objects.get(id=self.request.GET.get('item', None))
-        except (ValueError, StockItem.DoesNotExist):
-            pass
-
-        return initials
-
-    def get_form(self):
-
-        form = super().get_form()
-        form.fields['stock_item'].widget = HiddenInput()
-
-        return form
-
-
 class StockItemAttachmentEdit(AjaxUpdateView):
     """
     View for editing a StockItemAttachment object.
diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js
index 54f0ae2f16..10d07d07e2 100644
--- a/InvenTree/templates/js/forms.js
+++ b/InvenTree/templates/js/forms.js
@@ -304,10 +304,7 @@ function constructFormBody(fields, options) {
                 fields[field].prefix = `<span class='fas ${field_options.icon}'></span>`;
             }
 
-            // // Field value?
-            // if (fields[field].value == null) {
-            //     fields[field].value = field_options.value;
-            // }
+            fields[field].hidden = field_options.hidden;
         }
     }
 
@@ -672,6 +669,8 @@ function initializeRelatedFields(fields, options) {
 
         if (!field || field.type != 'related field') continue;
 
+        if (field.hidden) continue;
+
         if (!field.api_url) {
             // TODO: Provide manual api_url option?
             console.log(`Related field '${name}' missing 'api_url' parameter.`);
@@ -962,6 +961,11 @@ function constructField(name, parameters, options) {
 
     var field_name = `id_${name}`;
 
+    // Hidden inputs are rendered without label / help text / etc
+    if (parameters.hidden) {
+        return constructHiddenInput(name, parameters, options);
+    }
+
     var form_classes = 'form-group';
 
     if (parameters.errors) {
@@ -1142,6 +1146,18 @@ function constructInputOptions(name, classes, type, parameters) {
 }
 
 
+// Construct a "hidden" input
+function constructHiddenInput(name, parameters, options) {
+
+    return constructInputOptions(
+        name,
+        'hiddeninput',
+        'hidden',
+        parameters
+    );
+}
+
+
 // Construct a "checkbox" input
 function constructCheckboxInput(name, parameters, options) {
 
diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js
index 24e9c1d328..c9cf654d12 100644
--- a/InvenTree/templates/js/model_renderers.js
+++ b/InvenTree/templates/js/model_renderers.js
@@ -27,8 +27,27 @@ function renderCompany(name, data, parameters, options) {
 // Renderer for "StockItem" model
 function renderStockItem(name, data, parameters, options) {
 
-    // TODO - Include part detail, location, quantity
-    // TODO - Include part image
+    var image = data.part_detail.thumbnail || data.part_detail.image;
+
+    if (!image) {
+        image = `/static/img/blank_image.png`;
+    }
+
+    var html = `<img src='${image}' class='select2-thumbnail'>`;
+
+    html += ` <span>${data.part_detail.full_name || data.part_detail.name}</span>`;
+
+    if (data.serial && data.quantity == 1) {
+        html += ` - <i>{% trans "Serial Number" %}: ${data.serial}`;
+    } else {
+        html += ` - <i>{% trans "Quantity" %}: ${data.quantity}`;
+    }
+
+    if (data.part_detail.description) {
+        html += `<p><small>${data.part_detail.description}</small></p>`;
+    }
+
+    return html;
 }
 
 
@@ -62,7 +81,7 @@ function renderPart(name, data, parameters, options) {
 
     var html = `<img src='${image}' class='select2-thumbnail'>`;
     
-    html += ` <span>${data.full_name ?? data.name}</span>`;
+    html += ` <span>${data.full_name || data.name}</span>`;
 
     if (data.description) {
         html += ` - <i>${data.description}</i>`;