diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index deaac66d30..d0e1046448 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -2,7 +2,7 @@ from django import forms from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit -from .models import Part +from .models import Part, PartCategory class EditPartForm(forms.ModelForm): @@ -28,4 +28,26 @@ class EditPartForm(forms.ModelForm): 'URL', 'minimum_stock', 'trackable', + ] + + +class EditCategoryForm(forms.ModelForm): + + def __init__(self, *args, **kwargs): + super(EditCategoryForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + + self.helper.form_id = 'id-edit-part-form' + self.helper.form_class = 'blueForms' + self.helper.form_method = 'post' + #self.helper.form_action = 'submit' + + self.helper.add_input(Submit('submit', 'Submit')) + + class Meta: + model = PartCategory + fields = [ + 'parent', + 'name', + 'description' ] \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_delete.html b/InvenTree/part/templates/part/category_delete.html new file mode 100644 index 0000000000..03be834e30 --- /dev/null +++ b/InvenTree/part/templates/part/category_delete.html @@ -0,0 +1,50 @@ +{% extends 'base.html' %} + +{% block content %} + +
+
Are you sure you want to delete category '{{ category.name }}'?
+
+ +

Deleting this category is a permanent action and cannot be undone.

+ + {% if category.children.all|length > 0 %} +

This category contains {{ category.children.all|length }} child categories.
+ If this category is deleted, these child categories will be moved to + {% if category.parent %} + the '{{ category.parent.name }}' category. + {% else %} + the top level 'Parts' category. + {% endif %} +

+ + + {% endif %} + + {% if category.parts.all|length > 0 %} +

This category contains {{ category.parts.all|length }} parts.
+ {% if category.parent %} + If this category is deleted, these parts will be moved to the parent category '{{ category.parent.pathstring }}' + {% else %} + If this category is deleted, these parts will be moved to the top-level category 'Parts' + {% endif %} +

+ + {% endif %} + +
{% csrf_token %} + + +
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_detail.html b/InvenTree/part/templates/part/category_detail.html new file mode 100644 index 0000000000..ec602ff3af --- /dev/null +++ b/InvenTree/part/templates/part/category_detail.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + +{% load static %} + +{% block content %} + +{% include "part/cat_link.html" with category=category %} + +{% include "part/category_subcategories.html" with children=category.children.all %} + +{% include "part/category_parts.html" with parts=category.parts.all %} + +
+ + + + + + + + + + + + + + + +
+ +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_edit.html b/InvenTree/part/templates/part/category_edit.html new file mode 100644 index 0000000000..101ec0a167 --- /dev/null +++ b/InvenTree/part/templates/part/category_edit.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block content %} + +{% include "part/cat_link.html" with category=category %} + +
+
Edit details for category '{{ category.name }}'
+
+{% load crispy_forms_tags %} + +{% crispy form %} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_new.html b/InvenTree/part/templates/part/category_new.html new file mode 100644 index 0000000000..e46bdea222 --- /dev/null +++ b/InvenTree/part/templates/part/category_new.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% load static %} + +{% block content %} + +{% include "part/cat_link.html" with category=category %} + +
+
Create a new part category{% if category %} in category '{{ category.name }}'{% endif %}
+
+ +{% load crispy_forms_tags %} +{% crispy form %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_parts.html b/InvenTree/part/templates/part/category_parts.html new file mode 100644 index 0000000000..a08f7fd522 --- /dev/null +++ b/InvenTree/part/templates/part/category_parts.html @@ -0,0 +1,10 @@ +{% if parts|length > 0 %} +Parts: + +{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_subcategories.html b/InvenTree/part/templates/part/category_subcategories.html new file mode 100644 index 0000000000..548036cf1e --- /dev/null +++ b/InvenTree/part/templates/part/category_subcategories.html @@ -0,0 +1,11 @@ +{% if children|length > 0 %} +Subcategories: + +{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/edit.html b/InvenTree/part/templates/part/edit.html index d8eb692e3b..4e943ff22f 100644 --- a/InvenTree/part/templates/part/edit.html +++ b/InvenTree/part/templates/part/edit.html @@ -2,10 +2,14 @@ {% block details %} -Edit part information: +
+
Edit details for part '{{ part.name }}'
+
{% load crispy_forms_tags %} {% crispy form %} +
+ {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/index.html b/InvenTree/part/templates/part/index.html index 5710605fa2..e2c2c6c70b 100644 --- a/InvenTree/part/templates/part/index.html +++ b/InvenTree/part/templates/part/index.html @@ -5,31 +5,17 @@ {% include "part/cat_link.html" with category=category %} -{% if children|length > 0 %} -Subcategories: -
    -{% for child in children %} -
  • - {{ child.name }} - {{ child.description }} - {{ child.partcount }} -
  • -{% endfor %} -
-{% endif %} +{% include "part/category_subcategories.html" with children=children %} -{% if parts|length > 0 %} -Parts: -
    -{% for part in parts %} -
  • - {{ part.name }} - {{ part.description }} -
  • -{% endfor %} -
-{% endif %} +{% include "part/category_parts.html" with parts=parts %} - + {% endblock %} diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 6f2275c174..e59a75a520 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -52,16 +52,30 @@ part_detail_urls = [ url(r'^.*$', views.PartDetail.as_view(), name='part-detail'), ] +part_category_urls = [ + url(r'^edit/?', views.CategoryEdit.as_view(), name='category-edit'), + url(r'^delete/?', views.CategoryDelete.as_view(), name='category-delete'), + + url('^.*$', views.CategoryDetail.as_view(), name='category-detail'), +] + # URL list for part web interface part_urls = [ + + # Create a new category + url(r'^new_category/?', views.CategoryCreate.as_view(), name='category-create'), + # Create a new part - url(r'^create/?', views.PartCreate.as_view(), name='part-create'), + url(r'^new/?', views.PartCreate.as_view(), name='part-create'), # Individual url(r'^(?P\d+)/', include(part_detail_urls)), - url('list', views.PartIndex.as_view(), name='part-index'), - # ex: /part/5/ + # Part category + url(r'^category/(?P\d+)/', include(part_category_urls)), + + # Top level part list (display top level parts and categories) + url('', views.PartIndex.as_view(), name='part-index'), url(r'^.*$', RedirectView.as_view(url='list', permanent=False), name='part-index'), ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 995bbcdeda..6185eefb7c 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -8,7 +8,7 @@ from django.urls import reverse from django.views.generic import DetailView, ListView from django.views.generic.edit import UpdateView, DeleteView, CreateView -from .forms import EditPartForm +from .forms import EditPartForm, EditCategoryForm class PartIndex(ListView): model = Part @@ -16,21 +16,17 @@ class PartIndex(ListView): context_object_name = 'parts' def get_queryset(self): - self.category = self.request.GET.get('category', None) - - return Part.objects.filter(category=self.category) + return Part.objects.filter(category=None) def get_context_data(self, **kwargs): context = super(PartIndex, self).get_context_data(**kwargs) - children = PartCategory.objects.filter(parent=self.category) + # View top-level categories + children = PartCategory.objects.filter(parent=None) context['children'] = children - if self.category: - context['category'] = get_object_or_404(PartCategory, pk=self.category) - return context @@ -92,3 +88,61 @@ class PartDelete(DeleteView): else: return HttpResponseRedirect(self.get_object().get_absolute_url()) + +class CategoryDetail(DetailView): + model = PartCategory + context_object_name = 'category' + queryset = PartCategory.objects.all() + template_name = 'part/category_detail.html' + + +class CategoryEdit(UpdateView): + model = PartCategory + template_name = 'part/category_edit.html' + form_class = EditCategoryForm + + def get_context_data(self, **kwargs): + context = super(CategoryEdit, self).get_context_data(**kwargs).copy() + + context['category'] = get_object_or_404(PartCategory, pk=self.kwargs['pk']) + + return context + + +class CategoryDelete(DeleteView): + model = PartCategory + template_name = 'part/category_delete.html' + context_object_name = 'category' + success_url ='/part/' + + def post(self, request, *args, **kwargs): + if 'confirm' in request.POST: + return super(CategoryDelete, self).post(request, *args, **kwargs) + else: + return HttpResponseRedirect(self.get_object().get_absolute_url()) + + +class CategoryCreate(CreateView): + model = PartCategory + template_name = 'part/category_new.html' + form_class = EditCategoryForm + + def get_context_data(self, **kwargs): + context = super(CategoryCreate, self).get_context_data(**kwargs).copy() + + parent_id = self.request.GET.get('category', None) + + if parent_id: + context['category'] = get_object_or_404(PartCategory, pk=parent_id) + + return context + + def get_initial(self): + initials = super(CategoryCreate, self).get_initial().copy() + + parent_id = self.request.GET.get('category', None) + + if parent_id: + initials['parent'] = get_object_or_404(PartCategory, pk=parent_id) + + return initials