From 14132a6efac478f66ad071b13b2ffa4d67a243e8 Mon Sep 17 00:00:00 2001 From: Oliver Walters <oliver.henry.walters@gmail.com> Date: Thu, 7 May 2020 09:57:54 +1000 Subject: [PATCH] Add views / models / etc etc to support StockItem attachment --- InvenTree/part/views.py | 2 +- InvenTree/stock/forms.py | 16 +++- InvenTree/stock/models.py | 2 + .../templates/stock}/attachment_delete.html | 0 .../templates/stock/item_attachments.html | 82 +++++++++++++++++++ InvenTree/stock/templates/stock/tabs.html | 3 + InvenTree/stock/urls.py | 7 ++ InvenTree/stock/views.py | 75 ++++++++++++++++- InvenTree/templates/attachment_delete.html | 7 ++ 9 files changed, 191 insertions(+), 3 deletions(-) rename InvenTree/{part/templates/part => stock/templates/stock}/attachment_delete.html (100%) create mode 100644 InvenTree/stock/templates/stock/item_attachments.html create mode 100644 InvenTree/templates/attachment_delete.html diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 458696b75c..89a285cf60 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -135,7 +135,7 @@ class PartAttachmentDelete(AjaxDeleteView): model = PartAttachment ajax_form_title = _("Delete Part Attachment") - ajax_template_name = "part/attachment_delete.html" + ajax_template_name = "attachment_delete.html" context_object_name = "attachment" def get_data(self): diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index fef6ecc7a5..a4578440cb 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -13,7 +13,21 @@ from mptt.fields import TreeNodeChoiceField from InvenTree.helpers import GetExportFormats from InvenTree.forms import HelperForm -from .models import StockLocation, StockItem, StockItemTracking +from .models import StockLocation, StockItem, StockItemTracking, StockItemAttachment + + +class EditStockItemAttachmentForm(HelperForm): + """ + Form for creating / editing a StockItemAttachment object + """ + + class Meta: + model = StockItemAttachment + fields = [ + 'stock_item', + 'attachment', + 'comment' + ] class EditStockLocationForm(HelperForm): diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 6ab8ec07ee..ca5ae115a1 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -6,6 +6,8 @@ Stock database model definitions # -*- coding: utf-8 -*- from __future__ import unicode_literals +import os + from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from django.urls import reverse diff --git a/InvenTree/part/templates/part/attachment_delete.html b/InvenTree/stock/templates/stock/attachment_delete.html similarity index 100% rename from InvenTree/part/templates/part/attachment_delete.html rename to InvenTree/stock/templates/stock/attachment_delete.html diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html new file mode 100644 index 0000000000..6aeff554d0 --- /dev/null +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -0,0 +1,82 @@ +{% extends "stock/item_base.html" %} + +{% load static %} +{% load i18n %} + +{% block details %} + +{% include "stock/tabs.html" with tab='attachments' %} + +<hr> +<h4>{% trans "Stock Item Attachments" %}</h4> + + +<div id='attachment-buttons'> + <div class="btn-group"> + <button type='button' class='btn btn-success' id='new-attachment'>{% trans "Add Attachment" %}</button> + </div> +</div> + +<table class='table table-striped table-condensed' data-toolbar='#attachment-buttons' id='attachment-table'> + <thead> + <tr> + <th data-field='file' data-searchable='true'>{% trans "File" %}</th> + <th data-field='comment' data-searchable='true'>{% trans "Comment" %}</th> + <th></th> + </tr> + </thead> + <tbody> + {% for attachment in item.attachments.all %} + <tr> + <td><a href='/media/{{ attachment.attachment }}'>{{ attachment.basename }}</a></td> + <td>{{ attachment.comment }}</td> + <td> + <div class='btn-group' style='float: right;'> + <button type='button' class='btn btn-default btn-glyph attachment-edit-button' url="{% url 'stock-item-attachment-edit' attachment.id %}" data-toggle='tooltip' title='{% trans "Edit attachment" %}'> + <span class='fas fa-edit'/> + </button> + <button type='button' class='btn btn-default btn-glyph attachment-delete-button' url="{% url 'stock-item-attachment-delete' attachment.id %}" data-toggle='tooltip' title='{% trans "Delete attachment" %}'> + <span class='fas fa-trash-alt icon-red'/> + </button> + </div> + </td> + </tr> + {% endfor %} + </tbody> +</table> + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +$("#new-attachment").click(function() { + launchModalForm("{% url 'stock-item-attachment-create' %}?item={{ item.id }}", + { + reload: true, + }); +}); + +$("#attachment-table").on('click', '.attachment-edit-button', function() { + var button = $(this); + + launchModalForm(button.attr('url'), + { + reload: true, + }); +}); + +$("#attachment-table").on('click', '.attachment-delete-button', function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + success: function() { + location.reload(); + } + }); +}); + +$("#attachment-table").inventreeTable({ +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/tabs.html b/InvenTree/stock/templates/stock/tabs.html index 62ee68bc4b..5b69cac8b4 100644 --- a/InvenTree/stock/templates/stock/tabs.html +++ b/InvenTree/stock/templates/stock/tabs.html @@ -16,4 +16,7 @@ <li{% ifequal tab 'notes' %} class='active'{% endifequal %}> <a href="{% url 'stock-item-notes' item.id %}">{% trans "Notes" %}{% if item.notes %} <span class='fas fa-info-circle'></span>{% endif %}</a> </li> + <li{% if tab == 'attachments' %} class='active'{% endif %}> + <a href="{% url 'stock-item-attachments' item.id %}">{% trans "Attachments" %}{% if item.attachments.count > 0 %}<span class='badge'>{{ item.attachments.count }}</span>{% endif %}</a> + </li> </ul> \ No newline at end of file diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index f69dc8b63f..149c0dde2f 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -25,6 +25,7 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'), + url(r'^attachments/', views.StockItemDetail.as_view(template_name='stock/item_attachments.html'), name='stock-item-attachments'), url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), @@ -50,6 +51,12 @@ stock_urls = [ url(r'^item/new/?', views.StockItemCreate.as_view(), name='stock-item-create'), + 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'), + ])), + url(r'^track/', include(stock_tracking_urls)), url(r'^adjust/?', views.StockAdjust.as_view(), name='stock-adjust'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index b6ec8bda85..19edf8666d 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -26,7 +26,7 @@ from datetime import datetime from company.models import Company, SupplierPart from part.models import Part -from .models import StockItem, StockLocation, StockItemTracking +from .models import StockItem, StockLocation, StockItemTracking, StockItemAttachment from .admin import StockItemResource @@ -37,6 +37,7 @@ from .forms import AdjustStockForm from .forms import TrackingEntryForm from .forms import SerializeStockForm from .forms import ExportOptionsForm +from .forms import EditStockItemAttachmentForm class StockIndex(ListView): @@ -149,6 +150,78 @@ class StockLocationQRCode(QRCodeView): return None +class StockItemAttachmentCreate(AjaxCreateView): + """ + View for adding a new attachment for a StockItem + """ + + model = StockItemAttachment + form_class = EditStockItemAttachmentForm + ajax_form_title = _("Add Stock Item Attachment") + ajax_template_name = "modal_form.html" + + 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. + """ + + model = StockItemAttachment + form_class = EditStockItemAttachmentForm + ajax_form_title = _("Edit Stock Item Attachment") + + def get_form(self): + + form = super().get_form() + form.fields['stock_item'].widget = HiddenInput() + + return form + + +class StockItemAttachmentDelete(AjaxDeleteView): + """ + View for deleting a StockItemAttachment object. + """ + + model = StockItemAttachment + ajax_form_title = _("Delete Stock Item Attachment") + ajax_template_name = "attachment_delete.html" + context_object_name = "attachment" + + def get_data(self): + return { + 'danger': _("Deleted attachment"), + } + + class StockExportOptions(AjaxView): """ Form for selecting StockExport options """ diff --git a/InvenTree/templates/attachment_delete.html b/InvenTree/templates/attachment_delete.html new file mode 100644 index 0000000000..4ee7f03cb1 --- /dev/null +++ b/InvenTree/templates/attachment_delete.html @@ -0,0 +1,7 @@ +{% extends "modal_delete_form.html" %} +{% load i18n %} + +{% block pre_form_content %} +{% trans "Are you sure you want to delete this attachment?" %} +<br> +{% endblock %} \ No newline at end of file