Add form for creating a new StockItem allocation

This commit is contained in:
Oliver Walters 2020-04-22 21:26:38 +10:00
parent 2972aec759
commit 6ab03bd05a
5 changed files with 149 additions and 15 deletions

View File

@ -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>`;

View File

@ -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']

View File

@ -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}`);
html += makeIconButton('fa-shopping-cart', 'button-buy', pk, '{% trans "Buy parts" %}');
}
if (part.assembly) {
html += makeIconButton('fa-tools', `button-build-${pk}`);
html += makeIconButton('fa-tools', 'button-build', pk, '{% trans "Build parts" %}');
}
html += `</div>`;
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 %}

View File

@ -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

View File

@ -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