diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py
index de56ca34f7..d46138cd09 100644
--- a/InvenTree/build/forms.py
+++ b/InvenTree/build/forms.py
@@ -27,6 +27,18 @@ class EditBuildForm(HelperForm):
]
+class AutoAllocateBuildForm(HelperForm):
+ """ Form for auto-allocation of stock to a build """
+
+ confirm = forms.BooleanField(required=False, help_text='Confirm stock allocation')
+
+ class Meta:
+ model = Build
+ fields = [
+ 'confirm'
+ ]
+
+
class CompleteBuildForm(HelperForm):
""" Form for marking a Build as complete """
diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py
index fedcb76403..2c9077f3d7 100644
--- a/InvenTree/build/models.py
+++ b/InvenTree/build/models.py
@@ -127,10 +127,10 @@ class Build(models.Model):
- If there are multiple StockItems available, ignore (leave up to the user)
Returns:
- A dict object containing the StockItem objects to be allocated (and the quantities)
+ A list object containing the StockItem objects to be allocated (and the quantities)
"""
- allocations = {}
+ allocations = []
for item in self.part.bom_items.all():
@@ -151,12 +151,17 @@ class Build(models.Model):
# Are there any parts available?
if stock_item.quantity > 0:
+
# Only take as many as are available
if stock_item.quantity < q_required:
q_required = stock_item.quantity
- # Add the item to the allocations list
- allocations[stock_item] = q_required
+ allocation = {
+ 'stock_item': stock_item,
+ 'quantity': q_required,
+ }
+
+ allocations.append(allocation)
return allocations
@@ -164,6 +169,13 @@ class Build(models.Model):
def autoAllocate(self):
""" Run auto-allocation routine to allocate StockItems to this Build.
+ Returns a list of dict objects with keys like:
+
+ {
+ 'stock_item': item,
+ 'quantity': quantity,
+ }
+
See: getAutoAllocations()
"""
@@ -173,8 +185,8 @@ class Build(models.Model):
# Create a new allocation
build_item = BuildItem(
build=self,
- stock_item=item,
- quantity=allocations[item])
+ stock_item=item['stock_item'],
+ quantity=item['quantity'])
build_item.save()
diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html
index 1aa5338551..b3d7dd1009 100644
--- a/InvenTree/build/templates/build/allocate.html
+++ b/InvenTree/build/templates/build/allocate.html
@@ -18,7 +18,8 @@ InvenTree | Allocate Parts
+
+{% else %}
+No stock could be selected for automatic build allocation.
+{% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/build/templates/build/complete.html b/InvenTree/build/templates/build/complete.html
index 506f766c44..a2ebb26209 100644
--- a/InvenTree/build/templates/build/complete.html
+++ b/InvenTree/build/templates/build/complete.html
@@ -7,7 +7,7 @@ Are you sure you want to mark this build as complete?
{% if taking %}
The following items will be removed from stock:
-
+
{% for item in taking %}
{{ item.quantity }} x {{ item.stock_item.part.name }} from {{ item.stock_item.location }}
{% endfor %}
diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py
index 162b9a613f..ed0ee63289 100644
--- a/InvenTree/build/urls.py
+++ b/InvenTree/build/urls.py
@@ -21,6 +21,7 @@ build_detail_urls = [
url(r'^allocate/?', views.BuildAllocate.as_view(), name='build-allocate'),
url(r'^cancel/?', views.BuildCancel.as_view(), name='build-cancel'),
url(r'^complete/?', views.BuildComplete.as_view(), name='build-complete'),
+ url(r'^auto-allocate/?', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'),
url(r'^.*$', views.BuildDetail.as_view(), name='build-detail'),
]
diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py
index 19af4b6458..6575854704 100644
--- a/InvenTree/build/views.py
+++ b/InvenTree/build/views.py
@@ -12,7 +12,7 @@ from django.forms import HiddenInput
from part.models import Part
from .models import Build, BuildItem
-from .forms import EditBuildForm, EditBuildItemForm, CompleteBuildForm
+from .forms import EditBuildForm, EditBuildItemForm, CompleteBuildForm, AutoAllocateBuildForm
from stock.models import StockLocation, StockItem
from InvenTree.views import AjaxView, AjaxUpdateView, AjaxCreateView, AjaxDeleteView
@@ -67,6 +67,61 @@ class BuildCancel(AjaxView):
}
+class BuildAutoAllocate(AjaxUpdateView):
+ """ View to auto-allocate parts for a build.
+ Follows a simple set of rules to automatically allocate StockItem objects.
+
+ Ref: build.models.Build.getAutoAllocations()
+ """
+
+ model = Build
+ form_class = AutoAllocateBuildForm
+ context_object_name = 'build'
+ ajax_form_title = 'Allocate Stock'
+ ajax_template_name = 'build/auto_allocate.html'
+
+ def get_context_data(self, *args, **kwargs):
+ """ Get the context data for form rendering. """
+
+ context = {}
+
+ try:
+ build = Build.objects.get(id=self.kwargs['pk'])
+ context['build'] = build
+ context['allocations'] = build.getAutoAllocations()
+ except Build.DoesNotExist:
+ context['error'] = 'No matching buidl found'
+
+ return context
+
+ def post(self, request, *args, **kwargs):
+ """ Handle POST request. Perform auto allocations.
+
+ - If the form validation passes, perform allocations
+ - Otherwise, the form is passed back to the client
+ """
+
+ build = self.get_object()
+ form = self.get_form()
+
+ confirm = request.POST.get('confirm', False)
+
+ valid = False
+
+ if confirm is False:
+ form.errors['confirm'] = ['Confirm stock allocation']
+ form.non_field_errors = 'Check the confirmation box at the bottom of the list'
+ else:
+ build.autoAllocate()
+ valid = True
+
+ data = {
+ 'form_valid': valid,
+ }
+
+ return self.renderJsonResponse(request, form, data, context=self.get_context_data())
+
+
class BuildComplete(AjaxUpdateView):
""" View to mark a build as Complete.