mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	Merge pull request #3043 from maksimstojkovic/fr-2986-shipment-page-action
Complete Allocated Pending Orders from SO Page Actions Menu
This commit is contained in:
		| @@ -57,6 +57,7 @@ src="{% static 'img/blank_image.png' %}" | |||||||
|     <ul class='dropdown-menu' role='menu'> |     <ul class='dropdown-menu' role='menu'> | ||||||
|         <li><a class='dropdown-item' href='#' id='edit-order'><span class='fas fa-edit icon-green'></span> {% trans "Edit order" %}</a></li> |         <li><a class='dropdown-item' href='#' id='edit-order'><span class='fas fa-edit icon-green'></span> {% trans "Edit order" %}</a></li> | ||||||
|         {% if order.status == SalesOrderStatus.PENDING %} |         {% if order.status == SalesOrderStatus.PENDING %} | ||||||
|  |         <li><a class='dropdown-item' href='#' id='complete-order-shipments'><span class='fas fa-truck'></span> {% trans "Complete Shipments" %}</a></li> | ||||||
|         <li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li> |         <li><a class='dropdown-item' href='#' id='cancel-order'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel order" %}</a></li> | ||||||
|         {% endif %} |         {% endif %} | ||||||
|     </ul> |     </ul> | ||||||
| @@ -223,6 +224,16 @@ $("#edit-order").click(function() { | |||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | $("#complete-order-shipments").click(function() { | ||||||
|  |  | ||||||
|  |     completePendingShipments( | ||||||
|  |         {{ order.pk }}, | ||||||
|  |         { | ||||||
|  |             reload: true, | ||||||
|  |         } | ||||||
|  |     ); | ||||||
|  | }); | ||||||
|  |  | ||||||
| $("#cancel-order").click(function() { | $("#cancel-order").click(function() { | ||||||
|  |  | ||||||
|     cancelSalesOrder( |     cancelSalesOrder( | ||||||
|   | |||||||
| @@ -561,6 +561,11 @@ function constructFormBody(fields, options) { | |||||||
|         insertPersistButton(options); |         insertPersistButton(options); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Insert secondary buttons (if required) | ||||||
|  |     if (options.buttons) { | ||||||
|  |         insertSecondaryButtons(options); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Display the modal |     // Display the modal | ||||||
|     $(modal).modal('show'); |     $(modal).modal('show'); | ||||||
|  |  | ||||||
| @@ -650,6 +655,31 @@ function insertPersistButton(options) { | |||||||
|     $(options.modal).find('#modal-footer-buttons').append(html); |     $(options.modal).find('#modal-footer-buttons').append(html); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Add secondary buttons to the left of the close and submit buttons | ||||||
|  |  * with callback functions | ||||||
|  |  */ | ||||||
|  | function insertSecondaryButtons(options) { | ||||||
|  |     for (var idx = 0; idx < options.buttons.length; idx++) { | ||||||
|  |  | ||||||
|  |         var html = ` | ||||||
|  |         <button type="button" class="btn btn-outline-secondary" id="modal-form-${options.buttons[idx].name}"> | ||||||
|  |             ${options.buttons[idx].title} | ||||||
|  |         </button> | ||||||
|  |         `; | ||||||
|  |  | ||||||
|  |         $(options.modal).find('#modal-footer-secondary-buttons').append(html); | ||||||
|  |  | ||||||
|  |         if (options.buttons[idx].onClick instanceof Function) { | ||||||
|  |             // Copy callback reference to prevent errors if `idx` changes value before execution | ||||||
|  |             var onclick_callback = options.buttons[idx].onClick; | ||||||
|  |  | ||||||
|  |             $(options.modal).find(`#modal-form-${options.buttons[idx].name}`).click(function() { | ||||||
|  |                 onclick_callback(options); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Extract all specified form values as a single object |  * Extract all specified form values as a single object | ||||||
|   | |||||||
| @@ -75,6 +75,9 @@ function createNewModal(options={}) { | |||||||
|                     </div> |                     </div> | ||||||
|                     <span class='flex-item' style='flex-grow: 1;'></span> |                     <span class='flex-item' style='flex-grow: 1;'></span> | ||||||
|                     <h4><span id='modal-progress-spinner' class='fas fa-circle-notch fa-spin' style='display: none;'></span></h4> |                     <h4><span id='modal-progress-spinner' class='fas fa-circle-notch fa-spin' style='display: none;'></span></h4> | ||||||
|  |                     <div id='modal-footer-secondary-buttons'> | ||||||
|  |                         <!-- Extra secondary buttons can be inserted here --> | ||||||
|  |                     </div> | ||||||
|                     <button type='button' class='btn btn-secondary' id='modal-form-close' data-bs-dismiss='modal'>{% trans "Cancel" %}</button> |                     <button type='button' class='btn btn-secondary' id='modal-form-close' data-bs-dismiss='modal'>{% trans "Cancel" %}</button> | ||||||
|                     <button type='button' class='btn btn-${submitClass}' id='modal-form-submit'>{% trans "Submit" %}</button> |                     <button type='button' class='btn btn-${submitClass}' id='modal-form-submit'>{% trans "Submit" %}</button> | ||||||
|                 </div> |                 </div> | ||||||
| @@ -99,7 +102,7 @@ function createNewModal(options={}) { | |||||||
|         $(modal_name).focus(); |         $(modal_name).focus(); | ||||||
|  |  | ||||||
|         if (options.hideCloseButton) { |         if (options.hideCloseButton) { | ||||||
|             $(modal_name).find('#modal-form-cancel').hide(); |             $(modal_name).find('#modal-form-close').hide(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (options.preventSubmit || options.hideSubmitButton) { |         if (options.preventSubmit || options.hideSubmitButton) { | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
|     cancelSalesOrder, |     cancelSalesOrder, | ||||||
|     completePurchaseOrder, |     completePurchaseOrder, | ||||||
|     completeShipment, |     completeShipment, | ||||||
|  |     completePendingShipments, | ||||||
|     createSalesOrder, |     createSalesOrder, | ||||||
|     createSalesOrderShipment, |     createSalesOrderShipment, | ||||||
|     editPurchaseOrderLineItem, |     editPurchaseOrderLineItem, | ||||||
| @@ -69,7 +70,7 @@ function salesOrderShipmentFields(options={}) { | |||||||
| /* | /* | ||||||
|  * Complete a shipment |  * Complete a shipment | ||||||
|  */ |  */ | ||||||
| function completeShipment(shipment_id) { | function completeShipment(shipment_id, options={}) { | ||||||
|  |  | ||||||
|     // Request the list of stock items which will be shipped |     // Request the list of stock items which will be shipped | ||||||
|     inventreeGet(`/api/order/so/shipment/${shipment_id}/`, {}, { |     inventreeGet(`/api/order/so/shipment/${shipment_id}/`, {}, { | ||||||
| @@ -126,25 +127,125 @@ function completeShipment(shipment_id) { | |||||||
|  |  | ||||||
|             constructForm(`/api/order/so/shipment/${shipment_id}/ship/`, { |             constructForm(`/api/order/so/shipment/${shipment_id}/ship/`, { | ||||||
|                 method: 'POST', |                 method: 'POST', | ||||||
|                 title: '{% trans "Complete Shipment" %}', |                 title: `{% trans "Complete Shipment" %} ${shipment.reference}`, | ||||||
|                 fields: { |                 fields: { | ||||||
|                     tracking_number: {}, |                     tracking_number: {}, | ||||||
|                 }, |                 }, | ||||||
|                 preFormContent: html, |                 preFormContent: html, | ||||||
|                 confirm: true, |                 confirm: true, | ||||||
|                 confirmMessage: '{% trans "Confirm Shipment" %}', |                 confirmMessage: '{% trans "Confirm Shipment" %}', | ||||||
|  |                 buttons: options.buttons, | ||||||
|                 onSuccess: function(data) { |                 onSuccess: function(data) { | ||||||
|                     // Reload tables |                     // Reload tables | ||||||
|                     $('#so-lines-table').bootstrapTable('refresh'); |                     $('#so-lines-table').bootstrapTable('refresh'); | ||||||
|                     $('#pending-shipments-table').bootstrapTable('refresh'); |                     $('#pending-shipments-table').bootstrapTable('refresh'); | ||||||
|                     $('#completed-shipments-table').bootstrapTable('refresh'); |                     $('#completed-shipments-table').bootstrapTable('refresh'); | ||||||
|  |  | ||||||
|  |                     if (options.onSuccess instanceof Function) { | ||||||
|  |                         options.onSuccess(data); | ||||||
|  |                     } | ||||||
|                 }, |                 }, | ||||||
|                 reload: true |                 reload: options.reload | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Launches a modal to mark all allocated pending shipments as complete | ||||||
|  |  */ | ||||||
|  | function completePendingShipments(order_id, options={}) { | ||||||
|  |     var pending_shipments = null; | ||||||
|  |  | ||||||
|  |     // Request the list of stock items which will be shipped | ||||||
|  |     inventreeGet(`/api/order/so/shipment/.*`, | ||||||
|  |         { | ||||||
|  |             order: order_id, | ||||||
|  |             shipped: false | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             async: false, | ||||||
|  |             success: function(shipments) { | ||||||
|  |                 pending_shipments = shipments; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     var allocated_shipments = []; | ||||||
|  |  | ||||||
|  |     for (var idx = 0; idx < pending_shipments.length; idx++) { | ||||||
|  |         if (pending_shipments[idx].allocations.length > 0) { | ||||||
|  |             allocated_shipments.push(pending_shipments[idx]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (allocated_shipments.length > 0) { | ||||||
|  |         completePendingShipmentsHelper(allocated_shipments, 0, options); | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |         html = ` | ||||||
|  |         <div class='alert alert-block alert-danger'> | ||||||
|  |         `; | ||||||
|  |  | ||||||
|  |         if (!pending_shipments.length) { | ||||||
|  |             html += ` | ||||||
|  |             {% trans "No pending shipments found" %} | ||||||
|  |             `; | ||||||
|  |         } else { | ||||||
|  |             html += ` | ||||||
|  |             {% trans "No stock items have been allocated to pending shipments" %} | ||||||
|  |             `; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         html += ` | ||||||
|  |         </div> | ||||||
|  |         `; | ||||||
|  |  | ||||||
|  |         constructForm(`/api/order/so/shipment/0/ship/`, { | ||||||
|  |             method: 'POST', | ||||||
|  |             title: '{% trans "Complete Shipments" %}', | ||||||
|  |             preFormContent: html, | ||||||
|  |             onSubmit: function(fields, options) { | ||||||
|  |                 handleFormSuccess(fields, options); | ||||||
|  |             }, | ||||||
|  |             closeText: 'Close', | ||||||
|  |             hideSubmitButton: true, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Recursive helper for opening shipment completion modals | ||||||
|  |  */ | ||||||
|  | function completePendingShipmentsHelper(shipments, shipment_idx, options={}) { | ||||||
|  |     if (shipment_idx < shipments.length) { | ||||||
|  |         completeShipment(shipments[shipment_idx].pk, | ||||||
|  |             { | ||||||
|  |                 buttons: [ | ||||||
|  |                     { | ||||||
|  |                         name: 'skip', | ||||||
|  |                         title: `{% trans "Skip" %}`, | ||||||
|  |                         onClick: function(form_options) { | ||||||
|  |                             if (form_options.modal) { | ||||||
|  |                                 $(form_options.modal).modal('hide'); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  |                             completePendingShipmentsHelper(shipments, shipment_idx + 1, options); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 ], | ||||||
|  |                 onSuccess: function(data) { | ||||||
|  |                     completePendingShipmentsHelper(shipments, shipment_idx + 1, options); | ||||||
|  |                 }, | ||||||
|  |             } | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |     } else if (options.reload) { | ||||||
|  |         location.reload(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Launches a modal form to mark a PurchaseOrder as "complete" |  * Launches a modal form to mark a PurchaseOrder as "complete" | ||||||
|  */ |  */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user