Fixes for unit tests

This commit is contained in:
Oliver 2021-10-06 08:56:24 +11:00
parent 758e402a66
commit 95e7cc7a5d
5 changed files with 120 additions and 126 deletions

View File

@ -372,7 +372,7 @@
{ {
success: function(items) { success: function(items) {
adjustStock(action, items, { adjustStock(action, items, {
onSuccess: function() { success: function() {
location.reload(); location.reload();
} }
}); });

View File

@ -561,7 +561,7 @@ function itemAdjust(action) {
{ {
success: function(item) { success: function(item) {
adjustStock(action, [item], { adjustStock(action, [item], {
onSuccess: function() { success: function() {
location.reload(); location.reload();
} }
}); });

View File

@ -287,7 +287,7 @@
{ {
success: function(items) { success: function(items) {
adjustStock(action, items, { adjustStock(action, items, {
onSuccess: function() { success: function() {
location.reload(); location.reload();
} }
}); });

View File

@ -513,31 +513,34 @@ class StocktakeTest(StockAPITestCase):
# POST with a valid action # POST with a valid action
response = self.post(url, data) response = self.post(url, data)
self.assertContains(response, "must contain list", status_code=status.HTTP_400_BAD_REQUEST)
self.assertIn("This field is required", str(response.data["items"]))
data['items'] = [{ data['items'] = [{
'no': 'aa' 'no': 'aa'
}] }]
# POST without a PK # POST without a PK
response = self.post(url, data) response = self.post(url, data, expected_code=400)
self.assertContains(response, 'must contain a valid integer primary-key', status_code=status.HTTP_400_BAD_REQUEST)
self.assertIn('This field is required', str(response.data))
# POST with an invalid PK # POST with an invalid PK
data['items'] = [{ data['items'] = [{
'pk': 10 'pk': 10
}] }]
response = self.post(url, data) response = self.post(url, data, expected_code=400)
self.assertContains(response, 'does not match valid stock item', status_code=status.HTTP_400_BAD_REQUEST)
self.assertContains(response, 'object does not exist', status_code=status.HTTP_400_BAD_REQUEST)
# POST with missing quantity value # POST with missing quantity value
data['items'] = [{ data['items'] = [{
'pk': 1234 'pk': 1234
}] }]
response = self.post(url, data) response = self.post(url, data, expected_code=400)
self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST)
# POST with an invalid quantity value # POST with an invalid quantity value
data['items'] = [{ data['items'] = [{
@ -546,7 +549,7 @@ class StocktakeTest(StockAPITestCase):
}] }]
response = self.post(url, data) response = self.post(url, data)
self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) self.assertContains(response, 'A valid number is required', status_code=status.HTTP_400_BAD_REQUEST)
data['items'] = [{ data['items'] = [{
'pk': 1234, 'pk': 1234,
@ -554,18 +557,7 @@ class StocktakeTest(StockAPITestCase):
}] }]
response = self.post(url, data) response = self.post(url, data)
self.assertContains(response, 'must not be less than zero', status_code=status.HTTP_400_BAD_REQUEST) self.assertContains(response, 'Ensure this value is greater than or equal to 0', status_code=status.HTTP_400_BAD_REQUEST)
# Test with a single item
data = {
'item': {
'pk': 1234,
'quantity': '10',
}
}
response = self.post(url, data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_transfer(self): def test_transfer(self):
""" """
@ -573,24 +565,27 @@ class StocktakeTest(StockAPITestCase):
""" """
data = { data = {
'item': { 'items': [
'pk': 1234, {
'quantity': 10, 'pk': 1234,
}, 'quantity': 10,
}
],
'location': 1, 'location': 1,
'notes': "Moving to a new location" 'notes': "Moving to a new location"
} }
url = reverse('api-stock-transfer') url = reverse('api-stock-transfer')
response = self.post(url, data) # This should succeed
self.assertContains(response, "Moved 1 parts to", status_code=status.HTTP_200_OK) response = self.post(url, data, expected_code=201)
# Now try one which will fail due to a bad location # Now try one which will fail due to a bad location
data['location'] = 'not a location' data['location'] = 'not a location'
response = self.post(url, data) response = self.post(url, data, expected_code=400)
self.assertContains(response, 'Valid location must be specified', status_code=status.HTTP_400_BAD_REQUEST)
self.assertContains(response, 'Incorrect type. Expected pk value', status_code=status.HTTP_400_BAD_REQUEST)
class StockItemDeletionTest(StockAPITestCase): class StockItemDeletionTest(StockAPITestCase):

View File

@ -247,7 +247,7 @@ function adjustStock(action, items, options={}) {
break; break;
} }
var image = item.part_detail.thumbnail || item.part_detail.image || blankImage(); var thumb = thumbnailImage(item.part_detail.thumbnail || item.part_detail.image);
var status = stockStatusDisplay(item.status, { var status = stockStatusDisplay(item.status, {
classes: 'float-right' classes: 'float-right'
@ -268,14 +268,18 @@ function adjustStock(action, items, options={}) {
var actionInput = ''; var actionInput = '';
if (actionTitle != null) { if (actionTitle != null) {
actionInput = constructNumberInput( actionInput = constructField(
item.pk, `items_quantity_${pk}`,
{ {
value: value, type: 'decimal',
min_value: minValue, min_value: minValue,
max_value: maxValue, max_value: maxValue,
read_only: readonly, value: value,
title: readonly ? '{% trans "Quantity cannot be adjusted for serialized stock" %}' : '{% trans "Specify stock quantity" %}', title: readonly ? '{% trans "Quantity cannot be adjusted for serialized stock" %}' : '{% trans "Specify stock quantity" %}',
required: true,
},
{
hideLabels: true,
} }
); );
} }
@ -293,7 +297,7 @@ function adjustStock(action, items, options={}) {
html += ` html += `
<tr id='stock_item_${pk}' class='stock-item-row'> <tr id='stock_item_${pk}' class='stock-item-row'>
<td id='part_${pk}'><img src='${image}' class='hover-img-thumb'> ${item.part_detail.full_name}</td> <td id='part_${pk}'>${thumb} ${item.part_detail.full_name}</td>
<td id='stock_${pk}'>${quantity}${status}</td> <td id='stock_${pk}'>${quantity}${status}</td>
<td id='location_${pk}'>${location}</td> <td id='location_${pk}'>${location}</td>
<td id='action_${pk}'> <td id='action_${pk}'>
@ -319,50 +323,89 @@ function adjustStock(action, items, options={}) {
html += `</tbody></table>`; html += `</tbody></table>`;
var modal = createNewModal({ var extraFields = {};
title: formTitle,
});
// Extra fields if (specifyLocation) {
var extraFields = { extraFields.location = {};
location: {
label: '{% trans "Location" %}',
help_text: '{% trans "Select destination stock location" %}',
type: 'related field',
required: true,
api_url: `/api/stock/location/`,
model: 'stocklocation',
name: 'location',
},
notes: {
label: '{% trans "Notes" %}',
help_text: '{% trans "Stock transaction notes" %}',
type: 'string',
name: 'notes',
}
};
if (!specifyLocation) {
delete extraFields.location;
} }
constructFormBody({}, { if (action != 'delete') {
preFormContent: html, extraFields.notes = {};
}
constructForm(url, {
method: 'POST',
fields: extraFields, fields: extraFields,
preFormContent: html,
confirm: true, confirm: true,
confirmMessage: '{% trans "Confirm stock adjustment" %}', confirmMessage: '{% trans "Confirm stock adjustment" %}',
modal: modal, title: formTitle,
onSubmit: function(fields) { afterRender: function(fields, opts) {
// Add button callbacks to remove rows
$(opts.modal).find('.button-stock-item-remove').click(function() {
var pk = $(this).attr('pk');
// "Delete" action gets handled differently $(opts.modal).find(`#stock_item_${pk}`).remove();
});
// Initialize "location" field
if (specifyLocation) {
initializeRelatedField(
{
name: 'location',
type: 'related field',
model: 'stocklocation',
required: true,
},
null,
opts
);
}
},
onSubmit: function(fields, opts) {
// Extract data elements from the form
var data = {
items: [],
};
if (action != 'delete') {
data.notes = getFormFieldValue('notes', {}, opts);
}
if (specifyLocation) {
data.location = getFormFieldValue('location', {}, opts);
}
var item_pk_values = [];
items.forEach(function(item) {
var pk = item.pk;
// Does the row exist in the form?
var row = $(opts.modal).find(`#stock_item_${pk}`);
if (row) {
item_pk_values.push(pk);
var quantity = getFormFieldValue(`items_quantity_${pk}`, {}, opts);
data.items.push({
pk: pk,
quantity: quantity,
});
}
});
// Delete action is handled differently
if (action == 'delete') { if (action == 'delete') {
var requests = []; var requests = [];
items.forEach(function(item) { item_pk_values.forEach(function(pk) {
requests.push( requests.push(
inventreeDelete( inventreeDelete(
`/api/stock/${item.pk}/`, `/api/stock/${pk}/`,
) )
); );
}); });
@ -370,72 +413,40 @@ function adjustStock(action, items, options={}) {
// Wait for *all* the requests to complete // Wait for *all* the requests to complete
$.when.apply($, requests).done(function() { $.when.apply($, requests).done(function() {
// Destroy the modal window // Destroy the modal window
$(modal).modal('hide'); $(opts.modal).modal('hide');
if (options.onSuccess) { if (options.success) {
options.onSuccess(); options.success();
} }
}); });
return; return;
} }
// Data to transmit opts.nested = {
var data = { 'items': item_pk_values,
items: [],
}; };
// Add values for each selected stock item
items.forEach(function(item) {
var q = getFormFieldValue(item.pk, {}, {modal: modal});
if (q != null) {
data.items.push({pk: item.pk, quantity: q});
}
});
// Add in extra field data
for (var field_name in extraFields) {
data[field_name] = getFormFieldValue(
field_name,
fields[field_name],
{
modal: modal,
}
);
}
inventreePut( inventreePut(
url, url,
data, data,
{ {
method: 'POST', method: 'POST',
success: function() { success: function(response) {
// Hide the modal
$(opts.modal).modal('hide');
// Destroy the modal window if (options.success) {
$(modal).modal('hide'); options.success(response);
if (options.onSuccess) {
options.onSuccess();
} }
}, },
error: function(xhr) { error: function(xhr) {
switch (xhr.status) { switch (xhr.status) {
case 400: case 400:
handleFormErrors(xhr.responseJSON, fields, opts);
// Handle errors for standard fields
handleFormErrors(
xhr.responseJSON,
extraFields,
{
modal: modal,
}
);
break; break;
default: default:
$(modal).modal('hide'); $(opts.modal).modal('hide');
showApiError(xhr); showApiError(xhr);
break; break;
} }
@ -444,18 +455,6 @@ function adjustStock(action, items, options={}) {
); );
} }
}); });
// Attach callbacks for the action buttons
$(modal).find('.button-stock-item-remove').click(function() {
var pk = $(this).attr('pk');
$(modal).find(`#stock_item_${pk}`).remove();
});
attachToggle(modal);
$(modal + ' .select2-container').addClass('select-full-width');
$(modal + ' .select2-container').css('width', '100%');
} }
@ -1258,7 +1257,7 @@ function loadStockTable(table, options) {
var items = $(table).bootstrapTable('getSelections'); var items = $(table).bootstrapTable('getSelections');
adjustStock(action, items, { adjustStock(action, items, {
onSuccess: function() { success: function() {
$(table).bootstrapTable('refresh'); $(table).bootstrapTable('refresh');
} }
}); });