2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-30 12:36:45 +00:00
2019-05-07 23:03:05 +10:00

374 lines
10 KiB
Python

"""
Django views for interacting with Build objects
"""
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import get_object_or_404
from django.views.generic import DetailView, ListView
from django.forms import HiddenInput
from part.models import Part
from .models import Build, BuildItem
from .forms import EditBuildForm, EditBuildItemForm, CompleteBuildForm
from stock.models import StockLocation, StockItem
from InvenTree.views import AjaxView, AjaxUpdateView, AjaxCreateView, AjaxDeleteView
class BuildIndex(ListView):
""" View for displaying list of Builds
"""
model = Build
template_name = 'build/index.html'
context_object_name = 'builds'
def get_queryset(self):
""" Return all Build objects (order by date, newest first) """
return Build.objects.order_by('status', '-completion_date')
def get_context_data(self, **kwargs):
context = super(BuildIndex, self).get_context_data(**kwargs).copy()
context['active'] = self.get_queryset().filter(status__in=[Build.PENDING, ])
context['completed'] = self.get_queryset().filter(status=Build.COMPLETE)
context['cancelled'] = self.get_queryset().filter(status=Build.CANCELLED)
return context
class BuildCancel(AjaxView):
""" View to cancel a Build.
Provides a cancellation information dialog
"""
model = Build
ajax_template_name = 'build/cancel.html'
ajax_form_title = 'Cancel Build'
context_object_name = 'build'
fields = []
def post(self, request, *args, **kwargs):
""" Handle POST request. Mark the build status as CANCELLED """
build = get_object_or_404(Build, pk=self.kwargs['pk'])
build.cancelBuild(request.user)
return self.renderJsonResponse(request, None)
def get_data(self):
""" Provide JSON context data. """
return {
'danger': 'Build was cancelled'
}
class BuildComplete(AjaxUpdateView):
""" View to mark a build as Complete.
- Notifies the user of which parts will be removed from stock.
- Removes allocated items from stock
- Deletes pending BuildItem objects
"""
model = Build
form_class = CompleteBuildForm
context_object_name = "build"
ajax_form_title = "Complete Build"
ajax_template_name = "build/complete.html"
def get_initial(self):
""" Get initial form data for the CompleteBuild form
- If the part being built has a default location, pre-select that location
"""
initials = super(BuildComplete, self).get_initial().copy()
build = self.get_object()
if build.part.default_location is not None:
try:
location = StockLocation.objects.get(pk=build.part.default_location.id)
initials['location'] = location
except StockLocation.DoesNotExist:
pass
return initials
def get_context_data(self, **kwargs):
""" Get context data for passing to the rendered form
- Build information is required
"""
build = self.get_object()
# Build object
context = super(BuildComplete, self).get_context_data(**kwargs).copy()
context['build'] = build
# Items to be removed from stock
taking = BuildItem.objects.filter(build=build.id)
context['taking'] = taking
return context
def post(self, request, *args, **kwargs):
""" Handle POST request. Mark the build as COMPLETE
- If the form validation passes, the Build objects completeBuild() method is called
- Otherwise, the form is passed back to the client
"""
build = self.get_object()
form = self.get_form()
confirm = request.POST.get('confirm', False)
loc_id = request.POST.get('location', None)
valid = False
if confirm is False:
form.errors['confirm'] = [
'Confirm completion of build',
]
else:
try:
location = StockLocation.objects.get(id=loc_id)
valid = True
except StockLocation.DoesNotExist:
form.errors['location'] = ['Invalid location selected']
if valid:
build.completeBuild(location, request.user)
data = {
'form_valid': valid,
}
return self.renderJsonResponse(request, form, data)
def get_data(self):
""" Provide feedback data back to the form """
return {
'info': 'Build marked as COMPLETE'
}
class BuildDetail(DetailView):
""" Detail view of a single Build object. """
model = Build
template_name = 'build/detail.html'
context_object_name = 'build'
class BuildAllocate(DetailView):
""" View for allocating parts to a Build """
model = Build
context_object_name = 'build'
template_name = 'build/allocate.html'
def get_context_data(self, **kwargs):
""" Provide extra context information for the Build allocation page """
context = super(DetailView, self).get_context_data(**kwargs)
build = self.get_object()
part = build.part
bom_items = part.bom_items
context['part'] = part
context['bom_items'] = bom_items
return context
class BuildCreate(AjaxCreateView):
""" View to create a new Build object """
model = Build
context_object_name = 'build'
form_class = EditBuildForm
ajax_form_title = 'Start new Build'
ajax_template_name = 'modal_form.html'
def get_initial(self):
""" Get initial parameters for Build creation.
If 'part' is specified in the GET query, initialize the Build with the specified Part
"""
initials = super(BuildCreate, self).get_initial().copy()
part_id = self.request.GET.get('part', None)
if part_id:
try:
initials['part'] = Part.objects.get(pk=part_id)
except Part.DoesNotExist:
pass
return initials
def get_data(self):
return {
'success': 'Created new build',
}
class BuildUpdate(AjaxUpdateView):
""" View for editing a Build object """
model = Build
form_class = EditBuildForm
context_object_name = 'build'
ajax_form_title = 'Edit Build Details'
ajax_template_name = 'modal_form.html'
def get_data(self):
return {
'info': 'Edited build',
}
class BuildItemDelete(AjaxDeleteView):
""" View to 'unallocate' a BuildItem.
Really we are deleting the BuildItem object from the database.
"""
model = BuildItem
ajax_template_name = 'build/delete_build_item.html'
ajax_form_title = 'Unallocate Stock'
context_object_name = 'item'
def get_data(self):
return {
'danger': 'Removed parts from build allocation'
}
class BuildItemCreate(AjaxCreateView):
""" View for allocating a new part to a build """
model = BuildItem
form_class = EditBuildItemForm
ajax_template_name = 'modal_form.html'
ajax_form_title = 'Allocate new Part'
def get_form(self):
""" Create Form for making / editing new Part object """
form = super(AjaxCreateView, self).get_form()
# If the Build object is specified, hide the input field.
# We do not want the users to be able to move a BuildItem to a different build
build_id = form['build'].value()
if build_id is not None:
form.fields['build'].widget = HiddenInput()
# If the sub_part is supplied, limit to matching stock items
part_id = self.get_param('part')
if part_id:
try:
Part.objects.get(pk=part_id)
query = form.fields['stock_item'].queryset
# Only allow StockItem objects which match the current part
query = query.filter(part=part_id)
if build_id is not None:
# Exclude StockItem objects which are already allocated to this build and part
query = query.exclude(id__in=[item.stock_item.id for item in BuildItem.objects.filter(build=build_id, stock_item__part=part_id)])
form.fields['stock_item'].queryset = query
stocks = query.all()
# If there is only one item selected, select it
if len(stocks) == 1:
form.fields['stock_item'].initial = stocks[0].id
# There is no stock available
elif len(stocks) == 0:
# TODO - Add a message to the form describing the problem
pass
except Part.DoesNotExist:
pass
return form
def get_initial(self):
""" Provide initial data for BomItem. Look for the folllowing in the GET data:
- build: pk of the Build object
"""
initials = super(AjaxCreateView, self).get_initial().copy()
build_id = self.get_param('build')
part_id = self.get_param('part')
if part_id:
try:
part = Part.objects.get(pk=part_id)
except Part.DoesNotExist:
part = None
if build_id:
try:
build = Build.objects.get(pk=build_id)
initials['build'] = build
# Try to work out how many parts to allocate
if part:
unallocated = build.getUnallocatedQuantity(part)
initials['quantity'] = unallocated
except Build.DoesNotExist:
pass
return initials
class BuildItemEdit(AjaxUpdateView):
""" View to edit a BuildItem object """
model = BuildItem
ajax_template_name = 'modal_form.html'
form_class = EditBuildItemForm
ajax_form_title = 'Edit Stock Allocation'
def get_data(self):
return {
'info': 'Updated Build Item',
}
def get_form(self):
""" Create form for editing a BuildItem.
- Limit the StockItem options to items that match the part
"""
build_item = self.get_object()
form = super(BuildItemEdit, self).get_form()
query = StockItem.objects.all()
if build_item.stock_item:
part_id = build_item.stock_item.part.id
query = query.filter(part=part_id)
form.fields['stock_item'].queryset = query
form.fields['build'].widget = HiddenInput()
return form