mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 21:25: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