"Validate BOM" now uses the API also

This commit is contained in:
Oliver 2021-12-21 22:45:59 +11:00
parent 70f9a0fe13
commit 2c0da25cbc
8 changed files with 91 additions and 79 deletions

View File

@ -474,6 +474,56 @@ class PartCopyBOM(generics.CreateAPIView):
return ctx
class PartValidateBOM(generics.RetrieveUpdateAPIView):
"""
API endpoint for 'validating' the BOM for a given Part
"""
class BOMValidateSerializer(serializers.ModelSerializer):
class Meta:
model = Part
fields = [
'checksum',
'valid',
]
checksum = serializers.CharField(
read_only=True,
source='bom_checksum',
)
valid = serializers.BooleanField(
write_only=True,
default=False,
label=_('Valid'),
help_text=_('Validate entire Bill of Materials'),
)
def validate_valid(self, valid):
if not valid:
raise ValidationError(_('This option must be selected'))
queryset = Part.objects.all()
serializer_class = BOMValidateSerializer
def update(self, request, *args, **kwargs):
part = self.get_object()
partial = kwargs.pop('partial', False)
serializer = self.get_serializer(part, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
part.validate_bom(request.user)
return Response({
'checksum': part.bom_checksum,
})
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single Part object """
@ -1605,8 +1655,11 @@ part_api_urls = [
# Endpoint for extra serial number information
url(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'),
# Endpoint for duplicating a BOM
url(r'^copy-bom/', PartCopyBOM.as_view(), name='api-part-copy-bom'),
# Endpoint for duplicating a BOM for the specific Part
url(r'^bom-copy/', PartCopyBOM.as_view(), name='api-part-bom-copy'),
# Endpoint for validating a BOM for the specific Part
url(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'),
# Part detail endpoint
url(r'^.*$', PartDetail.as_view(), name='api-part-detail'),

View File

@ -55,21 +55,6 @@ class PartImageDownloadForm(HelperForm):
]
class BomValidateForm(HelperForm):
""" Simple confirmation form for BOM validation.
User is presented with a single checkbox input,
to confirm that the BOM for this part is valid
"""
validate = forms.BooleanField(required=False, initial=False, label=_('validate'), help_text=_('Confirm that the BOM is correct'))
class Meta:
model = Part
fields = [
'validate'
]
class BomMatchItemForm(MatchItemForm):
""" Override MatchItemForm fields """

View File

@ -1,12 +0,0 @@
{% extends "modal_form.html" %}
{% load i18n %}
{% block pre_form_content %}
{% blocktrans with part.full_name as part %}Confirm that the Bill of Materials (BOM) is valid for:<br><em>{{ part }}</em>{% endblocktrans %}
<div class='alert alert-warning alert-block'>
{% trans 'This will validate each line in the BOM.' %}
</div>
{% endblock %}

View File

@ -609,12 +609,10 @@
});
$("#validate-bom").click(function() {
launchModalForm(
"{% url 'bom-validate' part.id %}",
{
reload: true,
}
);
validateBom({{ part.id }}, {
reload: true
});
});
$("#download-bom").click(function () {

View File

@ -35,7 +35,6 @@ part_detail_urls = [
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'),
url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'),
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),

View File

@ -694,48 +694,6 @@ class PartImageSelect(AjaxUpdateView):
return self.renderJsonResponse(request, form, data)
class BomValidate(AjaxUpdateView):
"""
Modal form view for validating a part BOM
"""
model = Part
ajax_form_title = _("Validate BOM")
ajax_template_name = 'part/bom_validate.html'
context_object_name = 'part'
form_class = part_forms.BomValidateForm
def get_context(self):
return {
'part': self.get_object(),
}
def get(self, request, *args, **kwargs):
form = self.get_form()
return self.renderJsonResponse(request, form, context=self.get_context())
def validate(self, part, form, **kwargs):
confirm = str2bool(form.cleaned_data.get('validate', False))
if not confirm:
form.add_error('validate', _('Confirm that the BOM is valid'))
def save(self, part, form, **kwargs):
"""
Mark the BOM as validated
"""
part.validate_bom(self.request.user)
def get_data(self):
return {
'success': _('Validated Bill of Materials')
}
class BomUpload(InvenTreeRoleMixin, FileManagementFormView):
""" View for uploading a BOM file, and handling BOM data importing.

View File

@ -207,6 +207,11 @@ function showApiError(xhr, url) {
title = '{% trans "Error 404: Resource Not Found" %}';
message = '{% trans "The requested resource could not be located on the server" %}';
break;
// Method not allowed
case 405:
title = '{% trans "Error 405: Method Not Allowed" %}';
message = '{% trans "HTTP method not allowed at URL" %}';
break;
// Timeout
case 408:
title = '{% trans "Error 408: Timeout" %}';

View File

@ -40,6 +40,7 @@
loadStockPricingChart,
partStockLabel,
toggleStar,
validateBom,
*/
/* Part API functions
@ -429,9 +430,34 @@ function toggleStar(options) {
}
/* Validate a BOM */
function validateBom(part_id, options={}) {
var html = `
<div class='alert alert-block alert-success'>
{% trans "Validating the BOM will mark each line item as valid" %}
</div>
`;
constructForm(`/api/part/${part_id}/bom-validate/`, {
method: 'PUT',
fields: {
valid: {},
},
preFormContent: html,
title: '{% trans "Validate Bill of Materials" %}',
reload: options.reload,
onSuccess: function(response) {
showMessage('{% trans "Validated Bill of Materials" %}');
}
});
}
/* Duplicate a BOM */
function duplicateBom(part_id, options={}) {
constructForm(`/api/part/${part_id}/copy-bom/`, {
constructForm(`/api/part/${part_id}/bom-copy/`, {
method: 'POST',
fields: {
part: {