mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	ad UI components
This commit is contained in:
		| @@ -35,6 +35,29 @@ | ||||
|         <table class='table table-striped table-condensed' id='so-lines-table' data-toolbar='#order-toolbar-buttons'> | ||||
|         </table> | ||||
|     </div> | ||||
|  | ||||
|     <div class='panel-heading'> | ||||
|         <div class='d-flex flex-wrap'> | ||||
|             <h4>{% trans "Sales Order Lines" %}</h4> | ||||
|             {% include "spacer.html" %} | ||||
|             <div class='btn-group' role='group'> | ||||
|                 {% if roles.sales_order.change and order.is_pending %} | ||||
|                 <button type='button' class='btn btn-success' id='new-so-additional-line'> | ||||
|                     <span class='fas fa-plus-circle'></span> {% trans "Add Order Line" %} | ||||
|                 </button> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class='panel-content'> | ||||
|         <div id='order-additional-toolbar-buttons' class='btn-group' style='float: right;'> | ||||
|             <div class='btn-group'> | ||||
|                 {% include "filter_list.html" with id="sales-order-additional-lines" %} | ||||
|             </div> | ||||
|         </div> | ||||
|         <table class='table table-striped table-condensed' id='so-additional-lines-table' data-toolbar='#order-additional-toolbar-buttons'> | ||||
|         </table> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
| {% if order.is_pending %} | ||||
| @@ -245,6 +268,30 @@ | ||||
|         } | ||||
|     ); | ||||
|  | ||||
|     $("#new-so-additional-line").click(function() { | ||||
|  | ||||
|         var fields = soAdditionalLineItemFields({ | ||||
|             order: {{ order.pk }}, | ||||
|         }); | ||||
|  | ||||
|         constructForm('{% url "api-so-additional-line-list" %}', { | ||||
|             fields: fields, | ||||
|             method: 'POST', | ||||
|             title: '{% trans "Add Order Line" %}', | ||||
|             onSuccess: function() { | ||||
|                 $("#so-additional-lines-table").bootstrapTable("refresh"); | ||||
|             }, | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     loadSalesOrderAdditionalLineItemTable( | ||||
|         '#so-additional-lines-table', | ||||
|         { | ||||
|             order: {{ order.pk }}, | ||||
|             status: {{ order.status }}, | ||||
|         } | ||||
|     ); | ||||
|  | ||||
|     enableSidebar('salesorder'); | ||||
|      | ||||
| {% endblock %} | ||||
| @@ -30,6 +30,7 @@ | ||||
|     loadSalesOrderAllocationTable, | ||||
|     loadSalesOrderLineItemTable, | ||||
|     loadSalesOrderShipmentTable, | ||||
|     loadSalesOrderAdditionalLineItemTable | ||||
|     loadSalesOrderTable, | ||||
|     newPurchaseOrderFromOrderWizard, | ||||
|     newSupplierPartFromOrderWizard, | ||||
| @@ -305,6 +306,28 @@ function soLineItemFields(options={}) { | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Construct a set of fields for the SalesOrderAdditionalLineItem form */ | ||||
| function SOAdditionalLineItemFields(options={}) { | ||||
|  | ||||
|     var fields = { | ||||
|         order: { | ||||
|             hidden: true, | ||||
|         }, | ||||
|         quantity: {}, | ||||
|         reference: {}, | ||||
|         sale_price: {}, | ||||
|         sale_price_currency: {}, | ||||
|         notes: {}, | ||||
|     }; | ||||
|  | ||||
|     if (options.order) { | ||||
|         fields.order.value = options.order; | ||||
|     } | ||||
|  | ||||
|     return fields; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Construct a set of fields for the PurchaseOrderLineItem form */ | ||||
| function poLineItemFields(options={}) { | ||||
|  | ||||
| @@ -2773,3 +2796,241 @@ function loadSalesOrderLineItemTable(table, options={}) { | ||||
|         columns: columns, | ||||
|     }); | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Load a table displaying line items for a particular SalesOrder | ||||
|  *  | ||||
|  * @param {String} table : HTML ID tag e.g. '#table' | ||||
|  * @param {Object} options : object which contains: | ||||
|  *      - order {integer} : pk of the SalesOrder | ||||
|  *      - status: {integer} : status code for the order | ||||
|  */ | ||||
|  function loadSalesOrderAdditionalLineItemTable(table, options={}) { | ||||
|  | ||||
|     options.table = table; | ||||
|  | ||||
|     options.params = options.params || {}; | ||||
|  | ||||
|     if (!options.order) { | ||||
|         console.log('ERROR: function called without order ID'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!options.status) { | ||||
|         console.log('ERROR: function called without order status'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     options.params.order = options.order; | ||||
|     options.params.part_detail = true; | ||||
|     options.params.allocations = true; | ||||
|      | ||||
|     var filters = loadTableFilters('salesorderadditionallineitem'); | ||||
|  | ||||
|     for (var key in options.params) { | ||||
|         filters[key] = options.params[key]; | ||||
|     } | ||||
|  | ||||
|     options.url = options.url || '{% url "api-so-additional-line-list" %}'; | ||||
|  | ||||
|     var filter_target = options.filter_target || '#filter-list-sales-order-additional-lines'; | ||||
|  | ||||
|     setupFilterList('salesorderadditionallineitem', $(table), filter_target); | ||||
|  | ||||
|     // Is the order pending? | ||||
|     var pending = options.status == {{ SalesOrderStatus.PENDING }}; | ||||
|  | ||||
|     // Has the order shipped? | ||||
|     var shipped = options.status == {{ SalesOrderStatus.SHIPPED }}; | ||||
|  | ||||
|     // Show detail view if the PurchaseOrder is PENDING or SHIPPED | ||||
|     var show_detail = pending || shipped; | ||||
|  | ||||
|     // Table columns to display | ||||
|     var columns = [ | ||||
|         /* | ||||
|         { | ||||
|             checkbox: true, | ||||
|             visible: true, | ||||
|             switchable: false, | ||||
|         }, | ||||
|         */ | ||||
|         { | ||||
|             sortable: true, | ||||
|             field: 'reference', | ||||
|             title: '{% trans "Reference" %}', | ||||
|             switchable: true, | ||||
|         }, | ||||
|         { | ||||
|             sortable: true, | ||||
|             field: 'quantity', | ||||
|             title: '{% trans "Quantity" %}', | ||||
|             footerFormatter: function(data) { | ||||
|                 return data.map(function(row) { | ||||
|                     return +row['quantity']; | ||||
|                 }).reduce(function(sum, i) { | ||||
|                     return sum + i; | ||||
|                 }, 0); | ||||
|             }, | ||||
|             switchable: false, | ||||
|         }, | ||||
|         { | ||||
|             sortable: true, | ||||
|             field: 'sale_price', | ||||
|             title: '{% trans "Unit Price" %}', | ||||
|             formatter: function(value, row) { | ||||
|                 var formatter = new Intl.NumberFormat( | ||||
|                     'en-US', | ||||
|                     { | ||||
|                         style: 'currency', | ||||
|                         currency: row.sale_price_currency | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|                 return formatter.format(row.sale_price); | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             field: 'total_price', | ||||
|             sortable: true, | ||||
|             title: '{% trans "Total Price" %}', | ||||
|             formatter: function(value, row) { | ||||
|                 var formatter = new Intl.NumberFormat( | ||||
|                     'en-US', | ||||
|                     { | ||||
|                         style: 'currency', | ||||
|                         currency: row.sale_price_currency | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|                 return formatter.format(row.sale_price * row.quantity); | ||||
|             }, | ||||
|             footerFormatter: function(data) { | ||||
|                 var total = data.map(function(row) { | ||||
|                     return +row['sale_price'] * row['quantity']; | ||||
|                 }).reduce(function(sum, i) { | ||||
|                     return sum + i; | ||||
|                 }, 0); | ||||
|  | ||||
|                 var currency = (data.slice(-1)[0] && data.slice(-1)[0].sale_price_currency) || 'USD'; | ||||
|                  | ||||
|                 var formatter = new Intl.NumberFormat( | ||||
|                     'en-US', | ||||
|                     { | ||||
|                         style: 'currency',  | ||||
|                         currency: currency | ||||
|                     } | ||||
|                 ); | ||||
|                  | ||||
|                 return formatter.format(total); | ||||
|             } | ||||
|         } | ||||
|     ]; | ||||
|  | ||||
|     columns.push({ | ||||
|         field: 'notes', | ||||
|         title: '{% trans "Notes" %}', | ||||
|     }); | ||||
|  | ||||
|     if (pending) { | ||||
|         columns.push({ | ||||
|             field: 'buttons', | ||||
|             switchable: false, | ||||
|             formatter: function(value, row, index, field) { | ||||
|  | ||||
|                 var html = `<div class='btn-group float-right' role='group'>`; | ||||
|  | ||||
|                 var pk = row.pk; | ||||
|  | ||||
|                 html += makeIconButton('fa-clone', 'button-duplicate', pk, '{% trans "Duplicate line item" %}'); | ||||
|                 html += makeIconButton('fa-edit icon-blue', 'button-edit', pk, '{% trans "Edit line item" %}'); | ||||
|  | ||||
|                 var title = '{% trans "Delete line item" %}'; | ||||
|  | ||||
|                 // Prevent deletion of the line item if items have been allocated or shipped! | ||||
|                 html += makeIconButton('fa-trash-alt icon-red', 'button-delete', pk, title, ); | ||||
|  | ||||
|                 html += `</div>`; | ||||
|  | ||||
|                 return html; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function reloadTable() { | ||||
|         $(table).bootstrapTable('refresh'); | ||||
|     } | ||||
|  | ||||
|     // Configure callback functions once the table is loaded | ||||
|     function setupCallbacks() { | ||||
|  | ||||
|         // Callback for duplicating line items | ||||
|         $(table).find('.button-duplicate').click(function() { | ||||
|             var pk = $(this).attr('pk'); | ||||
|  | ||||
|             inventreeGet(`/api/order/so-additional-line/${pk}/`, {}, { | ||||
|                 success: function(data) { | ||||
|  | ||||
|                     var fields = soLineItemFields(); | ||||
|  | ||||
|                     constructForm('{% url "api-so-additional-line-list" %}', { | ||||
|                         method: 'POST', | ||||
|                         fields: fields, | ||||
|                         data: data, | ||||
|                         title: '{% trans "Duplicate Line Item" %}', | ||||
|                         onSuccess: function(response) { | ||||
|                             $(table).bootstrapTable('refresh'); | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Callback for editing line items | ||||
|         $(table).find('.button-edit').click(function() { | ||||
|             var pk = $(this).attr('pk'); | ||||
|  | ||||
|             constructForm(`/api/order/so-additional-line/${pk}/`, { | ||||
|                 fields: { | ||||
|                     quantity: {}, | ||||
|                     reference: {}, | ||||
|                     sale_price: {}, | ||||
|                     sale_price_currency: {}, | ||||
|                     target_date: {}, | ||||
|                     notes: {}, | ||||
|                 }, | ||||
|                 title: '{% trans "Edit Line Item" %}', | ||||
|                 onSuccess: reloadTable, | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Callback for deleting line items | ||||
|         $(table).find('.button-delete').click(function() { | ||||
|             var pk = $(this).attr('pk'); | ||||
|  | ||||
|             constructForm(`/api/order/so-additional-line/${pk}/`, { | ||||
|                 method: 'DELETE', | ||||
|                 title: '{% trans "Delete Line Item" %}', | ||||
|                 onSuccess: reloadTable, | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     $(table).inventreeTable({ | ||||
|         onPostBody: setupCallbacks, | ||||
|         name: 'salesorderadditionallineitems', | ||||
|         sidePagination: 'client', | ||||
|         formatNoMatches: function() { | ||||
|             return '{% trans "No matching line items" %}'; | ||||
|         }, | ||||
|         queryParams: filters, | ||||
|         original: options.params, | ||||
|         url: options.url, | ||||
|         showFooter: true, | ||||
|         uniqueId: 'pk', | ||||
|         detailView: show_detail, | ||||
|         detailViewByClick: false, | ||||
|         columns: columns, | ||||
|     }); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user