mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 13:05:42 +00:00
Merge remote-tracking branch 'inventree/master' into date-format
This commit is contained in:
@ -542,6 +542,11 @@ function constructFormBody(fields, options) {
|
||||
insertConfirmButton(options);
|
||||
}
|
||||
|
||||
// Insert "persist" button (if required)
|
||||
if (options.persist) {
|
||||
insertPersistButton(options);
|
||||
}
|
||||
|
||||
// Display the modal
|
||||
$(modal).modal('show');
|
||||
|
||||
@ -616,6 +621,22 @@ function insertConfirmButton(options) {
|
||||
}
|
||||
|
||||
|
||||
/* Add a checkbox to select if the modal will stay open after success */
|
||||
function insertPersistButton(options) {
|
||||
|
||||
var message = options.persistMessage || '{% trans "Keep this form open" %}';
|
||||
|
||||
var html = `
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="modal-persist">
|
||||
<label class="form-check-label" for="modal-persist">${message}</label>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$(options.modal).find('#modal-footer-buttons').append(html);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extract all specified form values as a single object
|
||||
*/
|
||||
@ -934,19 +955,40 @@ function getFormFieldValue(name, field={}, options={}) {
|
||||
*/
|
||||
function handleFormSuccess(response, options) {
|
||||
|
||||
// Close the modal
|
||||
if (!options.preventClose) {
|
||||
// Note: The modal will be deleted automatically after closing
|
||||
$(options.modal).modal('hide');
|
||||
}
|
||||
|
||||
// Display any required messages
|
||||
// Should we show alerts immediately or cache them?
|
||||
var cache = (options.follow && response.url) || options.redirect || options.reload;
|
||||
|
||||
// Should the form "persist"?
|
||||
var persist = false;
|
||||
|
||||
if (options.persist && options.modal) {
|
||||
// Determine if this form should "persist", or be dismissed?
|
||||
var chk = $(options.modal).find('#modal-persist');
|
||||
|
||||
persist = chk.exists() && chk.prop('checked');
|
||||
}
|
||||
|
||||
if (persist) {
|
||||
cache = false;
|
||||
}
|
||||
|
||||
var msg_target = null;
|
||||
|
||||
if (persist) {
|
||||
// If the modal is persistant, the target for any messages should be the modal!
|
||||
msg_target = $(options.modal).find('#pre-form-content');
|
||||
}
|
||||
|
||||
// Display any messages
|
||||
if (response && (response.success || options.successMessage)) {
|
||||
showAlertOrCache(response.success || options.successMessage, cache, {style: 'success'});
|
||||
showAlertOrCache(
|
||||
response.success || options.successMessage,
|
||||
cache,
|
||||
{
|
||||
style: 'success',
|
||||
target: msg_target,
|
||||
});
|
||||
}
|
||||
|
||||
if (response && response.info) {
|
||||
@ -961,20 +1003,41 @@ function handleFormSuccess(response, options) {
|
||||
showAlertOrCache(response.danger, cache, {style: 'danger'});
|
||||
}
|
||||
|
||||
if (options.onSuccess) {
|
||||
// Callback function
|
||||
options.onSuccess(response, options);
|
||||
}
|
||||
if (persist) {
|
||||
// Instead of closing the form and going somewhere else,
|
||||
// reload (empty) the form so the user can input more data
|
||||
|
||||
// Reset the status of the "submit" button
|
||||
if (options.modal) {
|
||||
$(options.modal).find('#modal-form-submit').prop('disabled', false);
|
||||
}
|
||||
|
||||
if (options.follow && response.url) {
|
||||
// Follow the returned URL
|
||||
window.location.href = response.url;
|
||||
} else if (options.reload) {
|
||||
// Reload the current page
|
||||
location.reload();
|
||||
} else if (options.redirect) {
|
||||
// Redirect to a specified URL
|
||||
window.location.href = options.redirect;
|
||||
// Remove any error flags from the form
|
||||
clearFormErrors(options);
|
||||
|
||||
} else {
|
||||
|
||||
// Close the modal
|
||||
if (!options.preventClose) {
|
||||
// Note: The modal will be deleted automatically after closing
|
||||
$(options.modal).modal('hide');
|
||||
}
|
||||
|
||||
if (options.onSuccess) {
|
||||
// Callback function
|
||||
options.onSuccess(response, options);
|
||||
}
|
||||
|
||||
if (options.follow && response.url) {
|
||||
// Follow the returned URL
|
||||
window.location.href = response.url;
|
||||
} else if (options.reload) {
|
||||
// Reload the current page
|
||||
location.reload();
|
||||
} else if (options.redirect) {
|
||||
// Redirect to a specified URL
|
||||
window.location.href = options.redirect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -988,6 +1051,8 @@ function clearFormErrors(options={}) {
|
||||
if (options && options.modal) {
|
||||
// Remove the individual error messages
|
||||
$(options.modal).find('.form-error-message').remove();
|
||||
|
||||
$(options.modal).find('.modal-content').removeClass('modal-error');
|
||||
|
||||
// Remove the "has error" class
|
||||
$(options.modal).find('.form-field-error').removeClass('form-field-error');
|
||||
@ -1884,7 +1949,7 @@ function getFieldName(name, options={}) {
|
||||
* - Field description (help text)
|
||||
* - Field errors
|
||||
*/
|
||||
function constructField(name, parameters, options) {
|
||||
function constructField(name, parameters, options={}) {
|
||||
|
||||
var html = '';
|
||||
|
||||
@ -1976,7 +2041,7 @@ function constructField(name, parameters, options) {
|
||||
html += `<div class='controls'>`;
|
||||
|
||||
// Does this input deserve "extra" decorators?
|
||||
var extra = parameters.prefix != null;
|
||||
var extra = (parameters.icon != null) || (parameters.prefix != null) || (parameters.prefixRaw != null);
|
||||
|
||||
// Some fields can have 'clear' inputs associated with them
|
||||
if (!parameters.required && !parameters.read_only) {
|
||||
@ -1998,9 +2063,13 @@ function constructField(name, parameters, options) {
|
||||
|
||||
if (extra) {
|
||||
html += `<div class='input-group'>`;
|
||||
|
||||
|
||||
if (parameters.prefix) {
|
||||
html += `<span class='input-group-text'>${parameters.prefix}</span>`;
|
||||
} else if (parameters.prefixRaw) {
|
||||
html += parameters.prefixRaw;
|
||||
} else if (parameters.icon) {
|
||||
html += `<span class='input-group-text'><span class='fas ${parameters.icon}'></span></span>`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2147,6 +2216,10 @@ function constructInputOptions(name, classes, type, parameters, options={}) {
|
||||
|
||||
opts.push(`type='${type}'`);
|
||||
|
||||
if (parameters.title || parameters.help_text) {
|
||||
opts.push(`title='${parameters.title || parameters.help_text}'`);
|
||||
}
|
||||
|
||||
// Read only?
|
||||
if (parameters.read_only) {
|
||||
opts.push(`readonly=''`);
|
||||
@ -2192,11 +2265,6 @@ function constructInputOptions(name, classes, type, parameters, options={}) {
|
||||
opts.push(`required=''`);
|
||||
}
|
||||
|
||||
// Custom mouseover title?
|
||||
if (parameters.title != null) {
|
||||
opts.push(`title='${parameters.title}'`);
|
||||
}
|
||||
|
||||
// Placeholder?
|
||||
if (parameters.placeholder != null) {
|
||||
opts.push(`placeholder='${parameters.placeholder}'`);
|
||||
|
@ -116,6 +116,10 @@ function makeIconButton(icon, cls, pk, title, options={}) {
|
||||
extraProps += `disabled='true' `;
|
||||
}
|
||||
|
||||
if (options.collapseTarget) {
|
||||
extraProps += `data-bs-toggle='collapse' href='#${options.collapseTarget}'`;
|
||||
}
|
||||
|
||||
html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}' ${extraProps}>`;
|
||||
html += `<span class='fas ${icon}'></span>`;
|
||||
html += `</button>`;
|
||||
|
@ -476,6 +476,19 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
quantity = 0;
|
||||
}
|
||||
|
||||
// Prepend toggles to the quantity input
|
||||
var toggle_batch = `
|
||||
<span class='input-group-text' title='{% trans "Add batch code" %}' data-bs-toggle='collapse' href='#div-batch-${pk}'>
|
||||
<span class='fas fa-layer-group'></span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
var toggle_serials = `
|
||||
<span class='input-group-text' title='{% trans "Add serial numbers" %}' data-bs-toggle='collapse' href='#div-serials-${pk}'>
|
||||
<span class='fas fa-hashtag'></span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
// Quantity to Receive
|
||||
var quantity_input = constructField(
|
||||
`items_quantity_${pk}`,
|
||||
@ -491,6 +504,36 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
}
|
||||
);
|
||||
|
||||
// Add in options for "batch code" and "serial numbers"
|
||||
var batch_input = constructField(
|
||||
`items_batch_code_${pk}`,
|
||||
{
|
||||
type: 'string',
|
||||
required: false,
|
||||
label: '{% trans "Batch Code" %}',
|
||||
help_text: '{% trans "Enter batch code for incoming stock items" %}',
|
||||
prefixRaw: toggle_batch,
|
||||
}
|
||||
);
|
||||
|
||||
var sn_input = constructField(
|
||||
`items_serial_numbers_${pk}`,
|
||||
{
|
||||
type: 'string',
|
||||
required: false,
|
||||
label: '{% trans "Serial Numbers" %}',
|
||||
help_text: '{% trans "Enter serial numbers for incoming stock items" %}',
|
||||
prefixRaw: toggle_serials,
|
||||
}
|
||||
);
|
||||
|
||||
// Hidden inputs below the "quantity" field
|
||||
var quantity_input_group = `${quantity_input}<div class='collapse' id='div-batch-${pk}'>${batch_input}</div>`;
|
||||
|
||||
if (line_item.part_detail.trackable) {
|
||||
quantity_input_group += `<div class='collapse' id='div-serials-${pk}'>${sn_input}</div>`;
|
||||
}
|
||||
|
||||
// Construct list of StockItem status codes
|
||||
var choices = [];
|
||||
|
||||
@ -528,16 +571,38 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
);
|
||||
|
||||
// Button to remove the row
|
||||
var delete_button = `<div class='btn-group float-right' role='group'>`;
|
||||
var buttons = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
delete_button += makeIconButton(
|
||||
buttons += makeIconButton(
|
||||
'fa-layer-group',
|
||||
'button-row-add-batch',
|
||||
pk,
|
||||
'{% trans "Add batch code" %}',
|
||||
{
|
||||
collapseTarget: `div-batch-${pk}`
|
||||
}
|
||||
);
|
||||
|
||||
if (line_item.part_detail.trackable) {
|
||||
buttons += makeIconButton(
|
||||
'fa-hashtag',
|
||||
'button-row-add-serials',
|
||||
pk,
|
||||
'{% trans "Add serial numbers" %}',
|
||||
{
|
||||
collapseTarget: `div-serials-${pk}`,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
buttons += makeIconButton(
|
||||
'fa-times icon-red',
|
||||
'button-row-remove',
|
||||
pk,
|
||||
'{% trans "Remove row" %}',
|
||||
);
|
||||
|
||||
delete_button += '</div>';
|
||||
buttons += '</div>';
|
||||
|
||||
var html = `
|
||||
<tr id='receive_row_${pk}' class='stock-receive-row'>
|
||||
@ -554,7 +619,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
${line_item.received}
|
||||
</td>
|
||||
<td id='quantity_${pk}'>
|
||||
${quantity_input}
|
||||
${quantity_input_group}
|
||||
</td>
|
||||
<td id='status_${pk}'>
|
||||
${status_input}
|
||||
@ -563,7 +628,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
${destination_input}
|
||||
</td>
|
||||
<td id='actions_${pk}'>
|
||||
${delete_button}
|
||||
${buttons}
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
@ -587,7 +652,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
<th>{% trans "Order Code" %}</th>
|
||||
<th>{% trans "Ordered" %}</th>
|
||||
<th>{% trans "Received" %}</th>
|
||||
<th style='min-width: 50px;'>{% trans "Receive" %}</th>
|
||||
<th style='min-width: 50px;'>{% trans "Quantity to Receive" %}</th>
|
||||
<th style='min-width: 150px;'>{% trans "Status" %}</th>
|
||||
<th style='min-width: 300px;'>{% trans "Destination" %}</th>
|
||||
<th></th>
|
||||
@ -678,13 +743,23 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
|
||||
var location = getFormFieldValue(`items_location_${pk}`, {}, opts);
|
||||
|
||||
if (quantity != null) {
|
||||
data.items.push({
|
||||
|
||||
var line = {
|
||||
line_item: pk,
|
||||
quantity: quantity,
|
||||
status: status,
|
||||
location: location,
|
||||
});
|
||||
};
|
||||
|
||||
if (getFormFieldElement(`items_batch_code_${pk}`).exists()) {
|
||||
line.batch_code = getFormFieldValue(`items_batch_code_${pk}`);
|
||||
}
|
||||
|
||||
if (getFormFieldElement(`items_serial_numbers_${pk}`).exists()) {
|
||||
line.serial_numbers = getFormFieldValue(`items_serial_numbers_${pk}`);
|
||||
}
|
||||
|
||||
data.items.push(line);
|
||||
item_pk_values.push(pk);
|
||||
}
|
||||
|
||||
@ -936,6 +1011,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
|
||||
reference: {},
|
||||
purchase_price: {},
|
||||
purchase_price_currency: {},
|
||||
target_date: {},
|
||||
destination: {},
|
||||
notes: {},
|
||||
},
|
||||
@ -977,7 +1053,11 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
|
||||
],
|
||||
{
|
||||
success: function() {
|
||||
// Reload the line item table
|
||||
$(table).bootstrapTable('refresh');
|
||||
|
||||
// Reload the "received stock" table
|
||||
$('#stock-table').bootstrapTable('refresh');
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -1117,6 +1197,28 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
|
||||
return formatter.format(total);
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'target_date',
|
||||
switchable: true,
|
||||
title: '{% trans "Target Date" %}',
|
||||
formatter: function(value, row) {
|
||||
if (row.target_date) {
|
||||
var html = row.target_date;
|
||||
|
||||
if (row.overdue) {
|
||||
html += `<span class='fas fa-calendar-alt icon-red float-right' title='{% trans "This line item is overdue" %}'></span>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
} else if (row.order_detail && row.order_detail.target_date) {
|
||||
return `<em>${row.order_detail.target_date}</em>`;
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: false,
|
||||
field: 'received',
|
||||
@ -1163,15 +1265,15 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
|
||||
|
||||
var pk = row.pk;
|
||||
|
||||
if (options.allow_receive && row.received < row.quantity) {
|
||||
html += makeIconButton('fa-sign-in-alt icon-green', 'button-line-receive', pk, '{% trans "Receive line item" %}');
|
||||
}
|
||||
|
||||
if (options.allow_edit) {
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-line-edit', pk, '{% trans "Edit line item" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-line-delete', pk, '{% trans "Delete line item" %}');
|
||||
}
|
||||
|
||||
if (options.allow_receive && row.received < row.quantity) {
|
||||
html += makeIconButton('fa-sign-in-alt', 'button-line-receive', pk, '{% trans "Receive line item" %}');
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
return html;
|
||||
@ -2223,6 +2325,28 @@ function loadSalesOrderLineItemTable(table, options={}) {
|
||||
return formatter.format(total);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'target_date',
|
||||
title: '{% trans "Target Date" %}',
|
||||
sortable: true,
|
||||
switchable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.target_date) {
|
||||
var html = row.target_date;
|
||||
|
||||
if (row.overdue) {
|
||||
html += `<span class='fas fa-calendar-alt icon-red float-right' title='{% trans "This line item is overdue" %}'></span>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
} else if (row.order_detail && row.order_detail.target_date) {
|
||||
return `<em>${row.order_detail.target_date}</em>`;
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (pending) {
|
||||
@ -2366,6 +2490,7 @@ function loadSalesOrderLineItemTable(table, options={}) {
|
||||
reference: {},
|
||||
sale_price: {},
|
||||
sale_price_currency: {},
|
||||
target_date: {},
|
||||
notes: {},
|
||||
},
|
||||
title: '{% trans "Edit Line Item" %}',
|
||||
|
@ -905,6 +905,28 @@ function loadPartPurchaseOrderTable(table, part_id, options={}) {
|
||||
field: 'quantity',
|
||||
title: '{% trans "Quantity" %}',
|
||||
},
|
||||
{
|
||||
field: 'target_date',
|
||||
title: '{% trans "Target Date" %}',
|
||||
switchable: true,
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.target_date) {
|
||||
var html = row.target_date;
|
||||
|
||||
if (row.overdue) {
|
||||
html += `<span class='fas fa-calendar-alt icon-red float-right' title='{% trans "This line item is overdue" %}'></span>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
} else if (row.order_detail && row.order_detail.target_date) {
|
||||
return `<em>${row.order_detail.target_date}</em>`;
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'received',
|
||||
title: '{% trans "Received" %}',
|
||||
|
Reference in New Issue
Block a user