mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Auto-generate build outputs when a build is created
This commit is contained in:
parent
170d55d64e
commit
22a5f921b8
@ -387,7 +387,7 @@ class AjaxCreateView(AjaxMixin, CreateView):
|
|||||||
|
|
||||||
self.pre_save(self.form, request)
|
self.pre_save(self.form, request)
|
||||||
self.object = self.form.save()
|
self.object = self.form.save()
|
||||||
self.post_save(new_object=self.object, request=request)
|
self.post_save(new_object=self.object, request=request, form=self.form, data=self.form.cleaned_data)
|
||||||
|
|
||||||
# Return the PK of the newly-created object
|
# Return the PK of the newly-created object
|
||||||
data['pk'] = self.object.pk
|
data['pk'] = self.object.pk
|
||||||
|
@ -23,6 +23,7 @@ class EditBuildForm(HelperForm):
|
|||||||
'reference': 'BO',
|
'reference': 'BO',
|
||||||
'link': 'fa-link',
|
'link': 'fa-link',
|
||||||
'batch': 'fa-layer-group',
|
'batch': 'fa-layer-group',
|
||||||
|
'serial-numbers': 'fa-hashtag',
|
||||||
'location': 'fa-map-marker-alt',
|
'location': 'fa-map-marker-alt',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +31,12 @@ class EditBuildForm(HelperForm):
|
|||||||
'reference': _('Build Order reference')
|
'reference': _('Build Order reference')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serial_numbers = forms.CharField(
|
||||||
|
label=_('Serial Numbers'),
|
||||||
|
help_text=_('Serial numbers for build outputs'),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Build
|
model = Build
|
||||||
fields = [
|
fields = [
|
||||||
@ -38,6 +45,7 @@ class EditBuildForm(HelperForm):
|
|||||||
'part',
|
'part',
|
||||||
'quantity',
|
'quantity',
|
||||||
'batch',
|
'batch',
|
||||||
|
'serial_numbers',
|
||||||
'take_from',
|
'take_from',
|
||||||
'destination',
|
'destination',
|
||||||
'parent',
|
'parent',
|
||||||
|
@ -24,6 +24,7 @@ from mptt.models import MPTTModel, TreeForeignKey
|
|||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus
|
from InvenTree.status_codes import BuildStatus
|
||||||
from InvenTree.helpers import increment, getSetting, normalize
|
from InvenTree.helpers import increment, getSetting, normalize
|
||||||
|
from InvenTree.helpers import ExtractSerialNumbers
|
||||||
from InvenTree.validators import validate_build_order_reference
|
from InvenTree.validators import validate_build_order_reference
|
||||||
from InvenTree.models import InvenTreeAttachment
|
from InvenTree.models import InvenTreeAttachment
|
||||||
|
|
||||||
@ -269,21 +270,46 @@ class Build(MPTTModel):
|
|||||||
|
|
||||||
return new_ref
|
return new_ref
|
||||||
|
|
||||||
def createInitialStockItem(self, user):
|
def createInitialStockItem(self, serial_numbers, user):
|
||||||
"""
|
"""
|
||||||
Create an initial output StockItem to be completed by this build.
|
Create an initial output StockItem to be completed by this build.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
output = StockModels.StockItem.objects.create(
|
if self.part.trackable:
|
||||||
part=self.part, # Link to the parent part
|
# Trackable part? Create individual build outputs?
|
||||||
location=None, # No location (yet) until it is completed
|
|
||||||
quantity=self.quantity,
|
|
||||||
batch='', # The 'batch' code is not set until the item is completed
|
|
||||||
build=self, # Point back to this build
|
|
||||||
is_building=True, # Mark this StockItem as building
|
|
||||||
)
|
|
||||||
|
|
||||||
output.save()
|
# Serial numbers specified for the build?
|
||||||
|
if serial_numbers:
|
||||||
|
serials = ExtractSerialNumbers(serial_numbers, self.quantity)
|
||||||
|
else:
|
||||||
|
serials = [None] * self.quantity
|
||||||
|
|
||||||
|
for serial in serials:
|
||||||
|
output = StockModels.StockItem.objects.create(
|
||||||
|
part=self.part,
|
||||||
|
location=self.destination,
|
||||||
|
quantity=1,
|
||||||
|
batch=self.batch,
|
||||||
|
serial=serial,
|
||||||
|
build=self,
|
||||||
|
is_building=True
|
||||||
|
)
|
||||||
|
|
||||||
|
output.save()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Create a single build output
|
||||||
|
|
||||||
|
output = StockModels.StockItem.objects.create(
|
||||||
|
part=self.part, # Link to the parent part
|
||||||
|
location=None, # No location (yet) until it is completed
|
||||||
|
quantity=self.quantity,
|
||||||
|
batch='', # The 'batch' code is not set until the item is completed
|
||||||
|
build=self, # Point back to this build
|
||||||
|
is_building=True, # Mark this StockItem as building
|
||||||
|
)
|
||||||
|
|
||||||
|
output.save()
|
||||||
|
|
||||||
# TODO - Add a transaction note to the new StockItem
|
# TODO - Add a transaction note to the new StockItem
|
||||||
|
|
||||||
|
@ -512,6 +512,18 @@ class BuildCreate(AjaxCreateView):
|
|||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
role_required = 'build.add'
|
role_required = 'build.add'
|
||||||
|
|
||||||
|
def get_form(self):
|
||||||
|
form = super().get_form()
|
||||||
|
|
||||||
|
if form['part'].value():
|
||||||
|
part = Part.objects.get(pk=form['part'].value())
|
||||||
|
|
||||||
|
# Part is not trackable - hide serial numbers
|
||||||
|
if not part.trackable:
|
||||||
|
form.fields['serial_numbers'].widget = HiddenInput()
|
||||||
|
|
||||||
|
return form
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
""" Get initial parameters for Build creation.
|
""" Get initial parameters for Build creation.
|
||||||
|
|
||||||
@ -547,6 +559,33 @@ class BuildCreate(AjaxCreateView):
|
|||||||
return {
|
return {
|
||||||
'success': _('Created new build'),
|
'success': _('Created new build'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def validate(self, cleaned_data, **kwargs):
|
||||||
|
"""
|
||||||
|
Perform extra form validation.
|
||||||
|
|
||||||
|
- If part is trackable, check that either batch or serial numbers are calculated
|
||||||
|
|
||||||
|
By this point form.is_valid() has been executed
|
||||||
|
"""
|
||||||
|
|
||||||
|
part = cleaned_data['part']
|
||||||
|
|
||||||
|
if part.trackable:
|
||||||
|
# For a trackable part, either batch or serial nubmber must be specified
|
||||||
|
if not cleaned_data['batch'] and not cleaned_data['serial_numbers']:
|
||||||
|
raise ValidationError({
|
||||||
|
'part': _('Trackable part must have either batch or serial number specified')
|
||||||
|
})
|
||||||
|
|
||||||
|
# If serial numbers are set...
|
||||||
|
serials = cleaned_data['serial_numbers']
|
||||||
|
quantity = cleaned_data['quantity']
|
||||||
|
|
||||||
|
extracted = ExtractSerialNumbers(serials, quantity)
|
||||||
|
|
||||||
|
# Ok, no errors...
|
||||||
|
return True
|
||||||
|
|
||||||
def post_save(self, **kwargs):
|
def post_save(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -555,8 +594,11 @@ class BuildCreate(AjaxCreateView):
|
|||||||
|
|
||||||
build = kwargs['new_object']
|
build = kwargs['new_object']
|
||||||
request = kwargs['request']
|
request = kwargs['request']
|
||||||
|
data = kwargs['data']
|
||||||
|
|
||||||
|
serials = data['serial_numbers']
|
||||||
|
|
||||||
build.createInitialStockItem(request.user)
|
build.createInitialStockItem(serials, request.user)
|
||||||
|
|
||||||
|
|
||||||
class BuildUpdate(AjaxUpdateView):
|
class BuildUpdate(AjaxUpdateView):
|
||||||
|
Loading…
Reference in New Issue
Block a user