client side form for assigning stock items to customers

This commit is contained in:
Oliver 2021-12-09 00:20:45 +11:00
parent c36687af22
commit 96a885e4e1
5 changed files with 168 additions and 54 deletions

View File

@ -21,20 +21,6 @@ from part.models import Part
from .models import StockLocation, StockItem, StockItemTracking
class AssignStockItemToCustomerForm(HelperForm):
"""
Form for manually assigning a StockItem to a Customer
TODO: This could be a simple API driven form!
"""
class Meta:
model = StockItem
fields = [
'customer',
]
class ReturnStockItemForm(HelperForm):
"""
Form for manually returning a StockItem into stock

View File

@ -568,11 +568,19 @@ $("#stock-convert").click(function() {
{% if item.in_stock %}
$("#stock-assign-to-customer").click(function() {
launchModalForm("{% url 'stock-item-assign' item.id %}",
{
reload: true,
inventreeGet('{% url "api-stock-detail" item.pk %}', {}, {
success: function(response) {
assignStockToCustomer(
[response],
{
success: function() {
location.reload();
},
}
);
}
);
});
});
$("#stock-move").click(function() {

View File

@ -23,7 +23,6 @@ stock_item_detail_urls = [
url(r'^delete/', views.StockItemDelete.as_view(), name='stock-item-delete'),
url(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'),
url(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'),
url(r'^assign/', views.StockItemAssignToCustomer.as_view(), name='stock-item-assign'),
url(r'^return/', views.StockItemReturnToStock.as_view(), name='stock-item-return'),
url(r'^install/', views.StockItemInstall.as_view(), name='stock-item-install'),

View File

@ -294,39 +294,6 @@ class StockLocationQRCode(QRCodeView):
return None
class StockItemAssignToCustomer(AjaxUpdateView):
"""
View for manually assigning a StockItem to a Customer
"""
model = StockItem
ajax_form_title = _("Assign to Customer")
context_object_name = "item"
form_class = StockForms.AssignStockItemToCustomerForm
def validate(self, item, form, **kwargs):
customer = form.cleaned_data.get('customer', None)
if not customer:
form.add_error('customer', _('Customer must be specified'))
def save(self, item, form, **kwargs):
"""
Assign the stock item to the customer.
"""
customer = form.cleaned_data.get('customer', None)
if customer:
item = item.allocateToCustomer(
customer,
user=self.request.user
)
item.clearAllocations()
class StockItemReturnToStock(AjaxUpdateView):
"""
View for returning a stock item (which is assigned to a customer) to stock.

View File

@ -38,6 +38,7 @@
*/
/* exported
assignStockToCustomer,
createNewStockItem,
createStockLocation,
duplicateStockItem,
@ -533,13 +534,166 @@ function exportStock(params={}) {
url += `&${key}=${params[key]}`;
}
console.log(url);
location.href = url;
}
});
}
/**
* Assign multiple stock items to a customer
*/
function assignStockToCustomer(items, options={}) {
// Generate HTML content for the form
var html = `
<table class='table table-striped table-condensed' id='stock-assign-table'>
<thead>
<tr>
<th>{% trans "Part" %}</th>
<th>{% trans "Stock Item" %}</th>
<th>{% trans "Location" %}</th>
<th></th>
</tr>
</thead>
<tbody>
`;
for (var idx = 0; idx < items.length; idx++) {
var item = items[idx];
var pk = item.pk;
var part = item.part_detail;
var thumbnail = thumbnailImage(part.thumbnail || part.image);
var status = stockStatusDisplay(item.status, {classes: 'float-right'});
var quantity = '';
if (item.serial && item.quantity == 1) {
quantity = `{% trans "Serial" %}: ${item.serial}`;
} else {
quantity = `{% trans "Quantity" %}: ${item.quantity}`;
}
quantity += status;
var location = locationDetail(item, false);
var buttons = `<div class='btn-group' role='group'>`;
buttons += makeIconButton(
'fa-times icon-red',
'button-stock-item-remove',
pk,
'{% trans "Remove row" %}',
);
buttons += '</div>';
html += `
<tr id='stock_item_${pk}' class='stock-item'row'>
<td id='part_${pk}'>${thumbnail} ${part.full_name}</td>
<td id='stock_${pk}'>
<div id='div_id_items_item_${pk}'>
${quantity}
<div id='errors-items_item_${pk}'></div>
</div>
</td>
<td id='location_${pk}'>${location}</td>
<td id='buttons_${pk}'>${buttons}</td>
</tr>
`;
}
html += `</tbody></table>`;
constructForm('{% url "api-stock-assign" %}', {
method: 'POST',
preFormContent: html,
fields: {
'customer': {
value: options.customer,
filters: {
is_customer: true,
},
},
'notes': {},
},
confirm: true,
confirmMessage: '{% trans "Confirm stock assignment" %}',
title: '{% trans "Assign Stock to Customer" %}',
afterRender: function(fields, opts) {
// Add button callbacks to remove rows
$(opts.modal).find('.button-stock-item-remove').click(function() {
var pk = $(this).attr('pk');
$(opts.modal).find(`#stock_item_${pk}`).remove();
});
},
onSubmit: function(fields, opts) {
// Extract data elements from the form
var data = {
customer: getFormFieldValue('customer', {}, opts),
notes: getFormFieldValue('notes', {}, opts),
items: [],
};
var item_pk_values = [];
items.forEach(function(item) {
var pk = item.pk;
// Does the row exist in the form?
var row = $(opts.modal).find(`#stock_item_${pk}`);
if (row) {
item_pk_values.push(pk);
data.items.push({
item: pk,
});
}
});
opts.nested = {
'items': item_pk_values,
}
inventreePut(
'{% url "api-stock-assign" %}',
data,
{
method: 'POST',
success: function(response) {
$(opts.modal).modal('hide');
if (options.success) {
options.success(response);
}
},
error: function(xhr) {
switch (xhr.status) {
case 400:
handleFormErrors(xhr.responseJSON, fields, opts);
break;
default:
$(opts.modal).modal('hide');
showApiError(xhr, opts.url);
break;
}
}
}
);
}
});
}
/**
* Perform stock adjustments
*/
@ -1098,7 +1252,7 @@ function locationDetail(row, showLink=true) {
// StockItem has been assigned to a sales order
text = '{% trans "Assigned to Sales Order" %}';
url = `/order/sales-order/${row.sales_order}/`;
} else if (row.location) {
} else if (row.location && row.location_detail) {
text = row.location_detail.pathstring;
url = `/stock/location/${row.location}/`;
} else {