mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add form for creating a new StockItem allocation
This commit is contained in:
parent
2972aec759
commit
6ab03bd05a
@ -78,16 +78,16 @@ function getImageUrlFromTransfer(transfer) {
|
||||
return url;
|
||||
}
|
||||
|
||||
function makeIconButton(icon, id, opts) {
|
||||
function makeIconButton(icon, cls, pk, title) {
|
||||
// Construct an 'icon button' using the fontawesome set
|
||||
|
||||
var options = opts || {};
|
||||
var classes = `btn btn-default btn-glyph ${cls}`;
|
||||
|
||||
var title = options.title || '';
|
||||
var id = `${cls}-${pk}`;
|
||||
|
||||
var html = '';
|
||||
|
||||
html += `<button id='${id}' class='btn btn-default btn-glyph' title='${title}'>`;
|
||||
html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}'>`;
|
||||
html += `<span class='fas ${icon}'></span>`;
|
||||
html += `</button>`;
|
||||
|
||||
|
@ -16,6 +16,7 @@ from InvenTree.fields import RoundingDecimalFormField
|
||||
from stock.models import StockLocation
|
||||
from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment
|
||||
from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment
|
||||
from .models import SalesOrderAllocation
|
||||
|
||||
|
||||
class IssuePurchaseOrderForm(HelperForm):
|
||||
@ -144,3 +145,16 @@ class EditSalesOrderLineItemForm(HelperForm):
|
||||
'reference',
|
||||
'notes'
|
||||
]
|
||||
|
||||
|
||||
class EditSalesOrderAllocationForm(HelperForm):
|
||||
|
||||
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5)
|
||||
|
||||
class Meta:
|
||||
model = SalesOrderAllocation
|
||||
|
||||
fields = [
|
||||
'line',
|
||||
'item',
|
||||
'quantity']
|
||||
|
@ -136,32 +136,78 @@ $("#so-lines-table").inventreeTable({
|
||||
field: 'buttons',
|
||||
formatter: function(value, row, index, field) {
|
||||
|
||||
var html = '';
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
var pk = row.pk;
|
||||
|
||||
if (row.part) {
|
||||
var part = row.part_detail;
|
||||
|
||||
html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
html += makeIconButton('fa-plus', `button-add-${pk}`);
|
||||
|
||||
if (part.purchaseable) {
|
||||
html += makeIconButton('fa-shopping-cart', `button-buy-${pk}`);
|
||||
}
|
||||
|
||||
if (part.assembly) {
|
||||
html += makeIconButton('fa-tools', `button-build-${pk}`);
|
||||
html += makeIconButton('fa-shopping-cart', 'button-buy', pk, '{% trans "Buy parts" %}');
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
if (part.assembly) {
|
||||
html += makeIconButton('fa-tools', 'button-build', pk, '{% trans "Build parts" %}');
|
||||
}
|
||||
|
||||
html += makeIconButton('fa-plus', 'button-add', pk, '{% trans "Allocate parts" %}');
|
||||
|
||||
}
|
||||
|
||||
html += makeIconButton('fa-edit', 'button-edit', pk, '{% trans "Edit line item" %}');
|
||||
html += `</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
function reloadTable() {
|
||||
$("#so-lines-table").bootstrapTable("refresh");
|
||||
}
|
||||
|
||||
// Called when the table is loaded
|
||||
$("#so-lines-table").on('load-success.bs.table', function() {
|
||||
|
||||
var table = $(this);
|
||||
|
||||
// Set up callbacks for the row buttons
|
||||
table.find(".button-edit").click(function() {
|
||||
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
launchModalForm(`/order/sales-order/line/${pk}/edit/`, {
|
||||
success: reloadTable,
|
||||
});
|
||||
console.log("clicked!");
|
||||
});
|
||||
|
||||
table.find(".button-add").click(function() {
|
||||
console.log("add");
|
||||
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
launchModalForm(`/order/sales-order/allocation/new/`, {
|
||||
reload: table,
|
||||
data: {
|
||||
line: pk,
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
table.find(".button-build").click(function() {
|
||||
console.log("build");
|
||||
|
||||
var pk = $(this).attr('pk');
|
||||
});
|
||||
|
||||
table.find(".button-buy").click(function() {
|
||||
console.log("buy");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -61,8 +61,12 @@ purchase_order_urls = [
|
||||
url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'),
|
||||
]
|
||||
|
||||
|
||||
so_line_urls = [
|
||||
url(r'^new/', views.SOLineItemCreate.as_view(), name='so-line-item-create'),
|
||||
url(r'^(?P<pk>\d+)/', include([
|
||||
url(r'^edit/', views.SOLineItemEdit.as_view(), name='so-line-item-edit')
|
||||
])),
|
||||
]
|
||||
|
||||
sales_order_attachment_urls = [
|
||||
@ -88,6 +92,11 @@ sales_order_urls = [
|
||||
|
||||
url(r'^line/', include(so_line_urls)),
|
||||
|
||||
# URLs for sales order allocations
|
||||
url(r'^allocation/', include([
|
||||
url(r'^new/', views.SalesOrderAllocationCreate.as_view(), name='so-allocation-create'),
|
||||
])),
|
||||
|
||||
url(r'^attachments/', include(sales_order_attachment_urls)),
|
||||
|
||||
# Display detail view for a single SalesOrder
|
||||
|
@ -17,6 +17,7 @@ from decimal import Decimal, InvalidOperation
|
||||
|
||||
from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment
|
||||
from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment
|
||||
from .models import SalesOrderAllocation
|
||||
from .admin import POLineItemResource
|
||||
from build.models import Build
|
||||
from company.models import Company, SupplierPart
|
||||
@ -1114,6 +1115,22 @@ class SOLineItemCreate(AjaxCreateView):
|
||||
return initials
|
||||
|
||||
|
||||
class SOLineItemEdit(AjaxUpdateView):
|
||||
""" View for editing a SalesOrderLineItem """
|
||||
|
||||
model = SalesOrderLineItem
|
||||
form_class = order_forms.EditSalesOrderLineItemForm
|
||||
ajax_form_title = _('Edit Line Item')
|
||||
|
||||
def get_form(self):
|
||||
form = super().get_form()
|
||||
|
||||
form.fields.pop('order')
|
||||
form.fields.pop('part')
|
||||
|
||||
return form
|
||||
|
||||
|
||||
class POLineItemEdit(AjaxUpdateView):
|
||||
""" View for editing a PurchaseOrderLineItem object in a modal form.
|
||||
"""
|
||||
@ -1144,3 +1161,51 @@ class POLineItemDelete(AjaxDeleteView):
|
||||
return {
|
||||
'danger': _('Deleted line item'),
|
||||
}
|
||||
|
||||
|
||||
class SalesOrderAllocationCreate(AjaxCreateView):
|
||||
""" View for creating a new SalesOrderAllocation """
|
||||
|
||||
model = SalesOrderAllocation
|
||||
form_class = order_forms.EditSalesOrderAllocationForm
|
||||
ajax_form_title = _('Allocate Stock to Order')
|
||||
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
|
||||
line = self.request.GET.get('line', None)
|
||||
|
||||
if line is not None:
|
||||
initials['line'] = SalesOrderLineItem.objects.get(pk=line)
|
||||
|
||||
return initials
|
||||
|
||||
def get_form(self):
|
||||
|
||||
form = super().get_form()
|
||||
|
||||
line_id = form['line'].value()
|
||||
|
||||
# If a line item has been specified, reduce the queryset for the stockitem accordingly
|
||||
try:
|
||||
line = SalesOrderLineItem.objects.get(pk=line_id)
|
||||
|
||||
queryset = form.fields['item'].queryset
|
||||
|
||||
# Ensure the part reference matches
|
||||
queryset = queryset.filter(part=line.part)
|
||||
|
||||
# Exclude StockItem which are already allocated to this order
|
||||
allocated = [allocation.item.pk for allocation in line.allocations.all()]
|
||||
|
||||
queryset = queryset.exclude(pk__in=allocated)
|
||||
|
||||
form.fields['item'].queryset = queryset
|
||||
|
||||
# Hide the 'line' field
|
||||
form.fields['line'].widget = HiddenInput()
|
||||
|
||||
except KeyError: # (ValueError, SalesOrderLineItem.DoesNotExist):
|
||||
pass
|
||||
|
||||
return form
|
||||
|
Loading…
Reference in New Issue
Block a user