- {% for item in build.incomplete_outputs %}
- {% include "build/allocation_card.html" with item=item tracked_items=build.has_tracked_bom_items %}
- {% endfor %}
-
- {% else %}
-
- {% trans "Create a new build output" %}
- {% trans "No incomplete build outputs remain." %}
- {% trans "Create a new build output using the button above" %}
-
- {% endif %}
-
-
-
-{% endif %}
-
-
-
-
- {% trans "Completed Build Outputs" %}
-
-
-
-
- {% include "stock_table.html" with read_only=True %}
-
- {% if build.take_from %}
- {{ build.take_from }}{% include "clip.html"%}
- {% else %}
- {% trans "Stock can be taken from any available location." %}
- {% endif %}
-
-
-
-
-
{% trans "Destination" %}
-
- {% if build.destination %}
-
- {{ build.destination }}
- {% include "clip.html"%}
- {% else %}
- {% trans "Destination location not specified" %}
- {% endif %}
-
+ {% if build.take_from %}
+ {{ build.take_from }}{% include "clip.html"%}
+ {% else %}
+ {% trans "Stock can be taken from any available location." %}
+ {% endif %}
+
+
+
+
+
{% trans "Destination" %}
+
+ {% if build.destination %}
+
+ {{ build.destination }}
+ {% include "clip.html"%}
+ {% else %}
+ {% trans "Destination location not specified" %}
+ {% endif %}
+
+
+
+
+
{% trans "Status" %}
+
{% build_status_label build.status %}
+
+
+
+
{% trans "Progress" %}
+
{{ build.completed }} / {{ build.quantity }}
+
+ {% if build.batch %}
+
+
+
{% trans "Batch" %}
+
{{ build.batch }}{% include "clip.html"%}
+
{% endif %}
-
-
-
-
{% trans "Completed" %}
- {% if build.completion_date %}
-
{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}
{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}
+ {% else %}
+
{% trans "Build not complete" %}
+ {% endif %}
+
+
+
+
+
+
+
{% trans "Child Build Orders" %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{% trans "Allocate Stock to Build" %}
+
+
+ {% if build.has_untracked_bom_items %}
+ {% if build.active %}
+
+
+
+
+
+ {% if build.areUntrackedPartsFullyAllocated %}
+
+ {% trans "Untracked stock has been fully allocated for this Build Order" %}
+
+ {% else %}
+
+ {% trans "Untracked stock has not been fully allocated for this Build Order" %}
+
+ {% endif %}
+ {% endif %}
+
+ {% else %}
+
+ {% trans "This Build Order does not have any associated untracked BOM items" %}
+
+ {% endif %}
+
+
+
+
+ {% if not build.is_complete %}
+
+
{% trans "Incomplete Build Outputs" %}
+
+
+
+ {% if build.active %}
+
+ {% endif %}
+
+
+ {% if build.incomplete_outputs %}
+
+ {% for item in build.incomplete_outputs %}
+ {% include "build/allocation_card.html" with item=item tracked_items=build.has_tracked_bom_items %}
+ {% endfor %}
+
+ {% else %}
+
+ {% trans "Create a new build output" %}
+ {% trans "No incomplete build outputs remain." %}
+ {% trans "Create a new build output using the button above" %}
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+ {% trans "Completed Build Outputs" %}
+
+
+
+
+ {% include "stock_table.html" with read_only=True prefix="build-" %}
+
+ {% blocktrans with full_name=part.full_name%}Showing stock for all variants of {{full_name}}{% endblocktrans %}
+
+ {% endif %}
+ {% include "stock_table.html" %}
+
+
-
-
-
-
-
-
-
{% trans "Part name" %}
-
{{ part.name }}{% include "clip.html"%}
-
- {% if part.IPN %}
-
-
-
{% trans "IPN" %}
-
{{ part.IPN }}{% include "clip.html"%}
-
- {% endif %}
- {% if part.revision %}
-
-
-
{% trans "Revision" %}
-
{{ part.revision }}{% include "clip.html"%}
-
- {% endif %}
- {% if part.trackable %}
-
-
-
{% trans "Latest Serial Number" %}
-
- {% if part.getLatestSerialNumber %}
- {{ part.getLatestSerialNumber }}{% include "clip.html"%}
- {% else %}
- {% trans "No serial numbers recorded" %}
+
- {% object_link 'part-variants' part.variant_of.id part.variant_of.full_name as link %}
+ {% object_link 'part-detail' part.variant_of.id part.variant_of.full_name as link %}
{% blocktrans %}This part is a variant of {{link}}{% endblocktrans %}
- {% if part.is_template and part.active %}
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
-
-{% block js_ready %}
-{{ block.super }}
-
- loadPartVariantTable($('#variants-table'), {{ part.pk }});
-
- $('#new-variant').click(function() {
- launchModalForm(
- "{% url 'make-part-variant' part.id %}",
- {
- follow: true,
- }
- );
- });
-
-{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py
index 3b6b245231..9779aac544 100644
--- a/InvenTree/part/test_views.py
+++ b/InvenTree/part/test_views.py
@@ -158,21 +158,6 @@ class PartDetailTest(PartViewTestCase):
class PartTests(PartViewTestCase):
""" Tests for Part forms """
- def test_part_edit(self):
-
- response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
-
- keys = response.context.keys()
- data = str(response.content)
-
- self.assertEqual(response.status_code, 200)
-
- self.assertIn('part', keys)
- self.assertIn('csrf_token', keys)
-
- self.assertIn('html_form', data)
- self.assertIn('"title":', data)
-
def test_part_create(self):
""" Launch form to create a new part """
response = self.client.get(reverse('part-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py
index 1fa7227f5e..2215e14785 100644
--- a/InvenTree/part/urls.py
+++ b/InvenTree/part/urls.py
@@ -36,7 +36,6 @@ part_parameter_urls = [
]
part_detail_urls = [
- url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'),
url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'),
url(r'^bom-export/?', views.BomExport.as_view(), name='bom-export'),
url(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'),
@@ -48,20 +47,6 @@ part_detail_urls = [
url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'),
- url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'),
- url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'),
- url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'),
- url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'),
- url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'),
- url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'),
- url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'),
- url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'),
- url(r'^orders/?', views.PartDetail.as_view(template_name='part/orders.html'), name='part-orders'),
- url(r'^sales-orders/', views.PartDetail.as_view(template_name='part/sales_orders.html'), name='part-sales-orders'),
- url(r'^tests/', views.PartDetail.as_view(template_name='part/part_tests.html'), name='part-test-templates'),
- url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'),
- url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'),
-
url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),
# Normal thumbnail with form
@@ -91,9 +76,6 @@ category_urls = [
url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'),
url(r'^parameters/', include(category_parameter_urls)),
- url(r'^subcategory/', views.CategoryDetail.as_view(template_name='part/subcategory.html'), name='category-subcategory'),
- url(r'^parametric/', views.CategoryParametric.as_view(), name='category-parametric'),
-
# Anything else
url(r'^.*$', views.CategoryDetail.as_view(), name='category-detail'),
]))
diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py
index 4acf5fcdb6..7919b7d412 100644
--- a/InvenTree/part/views.py
+++ b/InvenTree/part/views.py
@@ -754,6 +754,7 @@ class PartDetail(InvenTreeRoleMixin, DetailView):
context_object_name = 'part'
queryset = Part.objects.all().select_related('category')
template_name = 'part/detail.html'
+ form_class = part_forms.PartPriceForm
# Add in some extra context information based on query params
def get_context_data(self, **kwargs):
@@ -774,25 +775,12 @@ class PartDetail(InvenTreeRoleMixin, DetailView):
ctx = part.get_context_data(self.request)
context.update(**ctx)
- return context
-
-
-class PartPricingView(PartDetail):
- """ Detail view for Part object
- """
- context_object_name = 'part'
- template_name = 'part/order_prices.html'
- form_class = part_forms.PartPriceForm
-
- # Add in some extra context information based on query params
- def get_context_data(self, **kwargs):
- """ Provide extra context data to template """
- context = super().get_context_data(**kwargs)
-
+ # Pricing information
ctx = self.get_pricing(self.get_quantity())
ctx['form'] = self.form_class(initial=self.get_initials())
context.update(ctx)
+
return context
def get_quantity(self):
@@ -1084,40 +1072,6 @@ class PartImageSelect(AjaxUpdateView):
return self.renderJsonResponse(request, form, data)
-class PartEdit(AjaxUpdateView):
- """ View for editing Part object """
-
- model = Part
- form_class = part_forms.EditPartForm
- ajax_template_name = 'modal_form.html'
- ajax_form_title = _('Edit Part Properties')
- context_object_name = 'part'
-
- def get_form(self):
- """ Create form for Part editing.
- Overrides default get_form() method to limit the choices
- for the 'default_supplier' field to SupplierParts that reference this part
- """
-
- form = super(AjaxUpdateView, self).get_form()
-
- # Hide the "default expiry" field if the feature is not enabled
- if not inventree_settings.stock_expiry_enabled():
- form.fields['default_expiry'].widget = HiddenInput()
-
- part = self.get_object()
-
- form.fields['default_supplier'].queryset = SupplierPart.objects.filter(part=part)
-
- # Check if IPN can be edited
- ipn_edit_enable = InvenTreeSetting.get_setting('PART_ALLOW_EDIT_IPN')
- if not ipn_edit_enable and not self.request.user.is_superuser:
- # Admin can still change IPN
- form.fields['IPN'].disabled = True
-
- return form
-
-
class BomDuplicate(AjaxUpdateView):
"""
View for duplicating BOM from a parent item.
@@ -1475,7 +1429,7 @@ class BomUpload(InvenTreeRoleMixin, FileManagementFormView):
# BomItem already exists
pass
- return HttpResponseRedirect(reverse('part-bom', kwargs={'pk': self.kwargs['pk']}))
+ return HttpResponseRedirect(reverse('part-detail', kwargs={'pk': self.kwargs['pk']}))
class PartExport(AjaxView):
@@ -1852,7 +1806,7 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView):
model = PartCategory
context_object_name = 'category'
queryset = PartCategory.objects.all().prefetch_related('children')
- template_name = 'part/category_partlist.html'
+ template_name = 'part/category.html'
def get_context_data(self, **kwargs):
@@ -1863,18 +1817,6 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView):
except KeyError:
context['part_count'] = 0
- return context
-
-
-class CategoryParametric(CategoryDetail):
- """ Parametric view for PartCategory """
-
- template_name = 'part/category_parametric.html'
-
- def get_context_data(self, **kwargs):
-
- context = super(CategoryParametric, self).get_context_data(**kwargs).copy()
-
# Get current category
category = kwargs.get('object', None)
diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html
index 7564e7864e..8a00c1c5e6 100644
--- a/InvenTree/stock/templates/stock/item.html
+++ b/InvenTree/stock/templates/stock/item.html
@@ -3,44 +3,360 @@
{% load static %}
{% load inventree_extras %}
{% load i18n %}
+{% load markdownify %}
{% block menubar %}
-{% include "stock/navbar.html" with tab="tracking" %}
+{% include "stock/navbar.html" %}
{% endblock %}
-{% block heading %}
-{% trans "Stock Tracking Information" %}
-{% endblock %}
+{% block page_content %}
-{% block details %}
+
+
+
{% trans "Stock Tracking Information" %}
+
+
+ {% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
+ {% if owner_control.value == "True" %}
+ {% authorized_owners item.owner as owners %}
+ {% endif %}
+
+ {% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
+ {% if roles.stock.change and not item.is_building %}
+
+
+
+
+
+ {% endif %}
+ {% endif %}
+
+
+
+
-{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
-{% if owner_control.value == "True" %}
- {% authorized_owners item.owner as owners %}
-{% endif %}
+
+
+
{% trans "Child Stock Items" %}
+
+
+ {% if item.child_count > 0 %}
+ {% include "stock_table.html" with prefix="childs-" %}
+ {% else %}
+
+ {% trans "This stock item does not have any child items" %}
+
+ {% endif %}
+
+
-
+
+
+
{% trans "Test Data" %}
+
+
+
+
+
+ {% if user.is_staff %}
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+
-
-{% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
- {% if roles.stock.change and not item.is_building %}
-