mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add forms/views for manually assigning a stock item to a customer
This commit is contained in:
parent
d907136264
commit
80019a3ed8
@ -346,6 +346,8 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
|
||||
# Include context data about the updated object
|
||||
data['pk'] = obj.id
|
||||
|
||||
self.post_save(obj)
|
||||
|
||||
try:
|
||||
data['url'] = obj.get_absolute_url()
|
||||
except AttributeError:
|
||||
@ -353,6 +355,13 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
|
||||
|
||||
return self.renderJsonResponse(request, form, data)
|
||||
|
||||
def post_save(self, obj, *args, **kwargs):
|
||||
"""
|
||||
Hook called after the form data is saved.
|
||||
(Optional)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class AjaxDeleteView(AjaxMixin, UpdateView):
|
||||
|
||||
|
@ -632,24 +632,14 @@ class SalesOrderAllocation(models.Model):
|
||||
|
||||
order = self.line.order
|
||||
|
||||
item = self.item
|
||||
item = self.item.allocateToCustomer(
|
||||
order.customer,
|
||||
quantity=self.quantity,
|
||||
order=order,
|
||||
user=user
|
||||
)
|
||||
|
||||
# If the allocated quantity is less than the amount available,
|
||||
# then split the stock item into two lots
|
||||
if item.quantity > self.quantity:
|
||||
|
||||
# Grab a copy of the new stock item (which will keep track of its "parent")
|
||||
item = item.splitStock(self.quantity, None, user)
|
||||
|
||||
# Update our own reference to the new item
|
||||
self.item = item
|
||||
self.save()
|
||||
|
||||
# Assign the StockItem to the SalesOrder customer
|
||||
item.sales_order = order
|
||||
|
||||
# Clear the location
|
||||
item.location = None
|
||||
item.status = StockStatus.SHIPPED
|
||||
|
||||
item.save()
|
||||
# Update our own reference to the StockItem
|
||||
# (It may have changed if the stock was split)
|
||||
self.item = item
|
||||
self.save()
|
||||
|
@ -34,6 +34,18 @@ class EditStockItemAttachmentForm(HelperForm):
|
||||
]
|
||||
|
||||
|
||||
class AssignStockItemToCustomerForm(HelperForm):
|
||||
"""
|
||||
Form for manually assigning a StockItem to a Customer
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = StockItem
|
||||
fields = [
|
||||
'customer',
|
||||
]
|
||||
|
||||
|
||||
class EditStockItemTestResultForm(HelperForm):
|
||||
"""
|
||||
Form for creating / editing a StockItemTestResult object.
|
||||
|
@ -218,12 +218,6 @@ class StockItem(MPTTModel):
|
||||
|
||||
super().clean()
|
||||
|
||||
if self.status == StockStatus.SHIPPED and self.sales_order is None:
|
||||
raise ValidationError({
|
||||
'sales_order': "SalesOrder must be specified as status is marked as SHIPPED",
|
||||
'status': "Status cannot be marked as SHIPPED if the Customer is not set",
|
||||
})
|
||||
|
||||
if self.status == StockStatus.ASSIGNED_TO_OTHER_ITEM and self.belongs_to is None:
|
||||
raise ValidationError({
|
||||
'belongs_to': "Belongs_to field must be specified as statis is marked as ASSIGNED_TO_OTHER_ITEM",
|
||||
@ -442,6 +436,65 @@ class StockItem(MPTTModel):
|
||||
help_text=_('Stock Item Notes')
|
||||
)
|
||||
|
||||
def clearAllocations(self):
|
||||
"""
|
||||
Clear all order allocations for this StockItem:
|
||||
|
||||
- SalesOrder allocations
|
||||
- Build allocations
|
||||
"""
|
||||
|
||||
# Delete outstanding SalesOrder allocations
|
||||
self.sales_order_allocations.all().delete()
|
||||
|
||||
# Delete outstanding BuildOrder allocations
|
||||
self.allocations.all().delete()
|
||||
|
||||
def allocateToCustomer(self, customer, quantity=None, order=None, user=None, notes=None):
|
||||
"""
|
||||
Allocate a StockItem to a customer.
|
||||
|
||||
This action can be called by the following processes:
|
||||
- Completion of a SalesOrder
|
||||
- User manually assigns a StockItem to the customer
|
||||
|
||||
Args:
|
||||
customer: The customer (Company) to assign the stock to
|
||||
quantity: Quantity to assign (if not supplied, total quantity is used)
|
||||
order: SalesOrder reference
|
||||
user: User that performed the action
|
||||
notes: Notes field
|
||||
"""
|
||||
|
||||
if quantity is None:
|
||||
quantity = self.quantity
|
||||
|
||||
if quantity >= self.quantity:
|
||||
item = self
|
||||
else:
|
||||
item = self.splitStock(quantity, None, user)
|
||||
|
||||
# Update StockItem fields with new information
|
||||
item.sales_order = order
|
||||
item.status = StockStatus.SHIPPED
|
||||
item.customer = customer
|
||||
item.location = None
|
||||
|
||||
item.save()
|
||||
|
||||
# TODO - Remove any stock item allocations from this stock item
|
||||
|
||||
item.addTransactionNote(
|
||||
_("Assigned to Customer"),
|
||||
user,
|
||||
notes=_("Manually assigned to customer") + " " + customer.name,
|
||||
system=True
|
||||
)
|
||||
|
||||
# Return the reference to the stock item
|
||||
return item
|
||||
|
||||
|
||||
# If stock item is incoming, an (optional) ETA field
|
||||
# expected_arrival = models.DateField(null=True, blank=True)
|
||||
|
||||
|
@ -332,6 +332,16 @@ $("#show-qr-code").click(function() {
|
||||
|
||||
{% if item.in_stock %}
|
||||
|
||||
{% if item.part.salable %}
|
||||
$("#stock-assign-to-customer").click(function() {
|
||||
launchModalForm("{% url 'stock-item-assign' item.id %}",
|
||||
{
|
||||
reload: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
function itemAdjust(action) {
|
||||
launchModalForm("/stock/adjust/",
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ 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'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
|
||||
|
||||
|
@ -223,6 +223,44 @@ class StockItemAttachmentDelete(AjaxDeleteView):
|
||||
}
|
||||
|
||||
|
||||
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 post(self, request, *args, **kwargs):
|
||||
|
||||
customer = request.POST.get('customer', None)
|
||||
|
||||
if customer:
|
||||
try:
|
||||
customer = Company.objects.get(pk=customer)
|
||||
except (ValueError, Company.DoesNotExist):
|
||||
customer = None
|
||||
|
||||
if customer is not None:
|
||||
stock_item = self.get_object()
|
||||
|
||||
item = stock_item.allocateToCustomer(
|
||||
customer,
|
||||
user=request.user
|
||||
)
|
||||
|
||||
item.clearAllocations()
|
||||
|
||||
data = {
|
||||
'form_valid': True,
|
||||
}
|
||||
|
||||
return self.renderJsonResponse(request, self.get_form(), data)
|
||||
|
||||
|
||||
|
||||
class StockItemDeleteTestData(AjaxUpdateView):
|
||||
"""
|
||||
View for deleting all test data
|
||||
|
Loading…
Reference in New Issue
Block a user