Add ability to set stock status when receiving goods

This commit is contained in:
Oliver Walters 2020-05-03 09:50:00 +10:00
parent fe87bba577
commit 7430abc237
5 changed files with 71 additions and 17 deletions

View File

@ -54,6 +54,10 @@ class StatusCode:
return codes return codes
@classmethod
def text(cls, key):
return cls.options.get(key, None)
@classmethod @classmethod
def items(cls): def items(cls):
return cls.options.items() return cls.options.items()
@ -204,6 +208,15 @@ class StockStatus(StatusCode):
ASSIGNED_TO_OTHER_ITEM, ASSIGNED_TO_OTHER_ITEM,
] ]
# The following codes are available for receiving goods
RECEIVING_CODES = [
OK,
ATTENTION,
DAMAGED,
DESTROYED,
REJECTED
]
class BuildStatus(StatusCode): class BuildStatus(StatusCode):

View File

@ -209,7 +209,7 @@ class PurchaseOrder(Order):
return self.pending_line_items().count() == 0 return self.pending_line_items().count() == 0
@transaction.atomic @transaction.atomic
def receive_line_item(self, line, location, quantity, user): def receive_line_item(self, line, location, quantity, user, status=StockStatus.OK):
""" Receive a line item (or partial line item) against this PO """ Receive a line item (or partial line item) against this PO
""" """
@ -230,7 +230,9 @@ class PurchaseOrder(Order):
supplier_part=line.part, supplier_part=line.part,
location=location, location=location,
quantity=quantity, quantity=quantity,
purchase_order=self) purchase_order=self,
status=status
)
stock.save() stock.save()

View File

@ -1,23 +1,28 @@
{% extends "modal_form.html" %} {% extends "modal_form.html" %}
{% load i18n %}
{% load inventree_extras %}
{% load status_codes %}
{% block form %} {% block form %}
Receive outstanding parts for <b>{{ order }}</b> - <i>{{ order.description }}</i> {% trans "Receive outstanding parts for" %} <b>{{ order }}</b> - <i>{{ order.description }}</i>
<form method='post' action='' class='js-modal-form' enctype='multipart/form-data'> <form method='post' action='' class='js-modal-form' enctype='multipart/form-data'>
{% csrf_token %} {% csrf_token %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
<label class='control-label'>Parts</label> <label class='control-label'>{% trans "Parts" %}</label>
<p class='help-block'>Select parts to receive against this order.</p> <p class='help-block'>{% trans "Select parts to receive against this order" %}</p>
<table class='table table-striped'> <table class='table table-striped'>
<tr> <tr>
<th>Part</th> <th>{% trans "Part" %}</th>
<th>Order Code</th> <th>{% trans "Order Code" %}</th>
<th>On Order</th> <th>{% trans "On Order" %}</th>
<th>Received</th> <th>{% trans "Received" %}</th>
<th>Receive</th> <th>{% trans "Receive" %}</th>
<th>{% trans "Status" %}</th>
<th></th>
</tr> </tr>
{% for line in lines %} {% for line in lines %}
<tr id='line_row_{{ line.id }}'> <tr id='line_row_{{ line.id }}'>
@ -28,20 +33,29 @@ Receive outstanding parts for <b>{{ order }}</b> - <i>{{ order.description }}</i
</td> </td>
<td>{{ line.part.SKU }}</td> <td>{{ line.part.SKU }}</td>
{% else %} {% else %}
<td colspan='2'>Referenced part has been removed</td> <td colspan='2'>{% trans "Error: Referenced part has been removed" %}</td>
{% endif %} {% endif %}
<td>{{ line.quantity }}</td> <td>{% decimal line.quantity %}</td>
<td>{{ line.received }}</td> <td>{% decimal line.received %}</td>
<td> <td>
<div class='control-group'> <div class='control-group'>
<div class='controls'> <div class='controls'>
<input class='numberinput' type='number' min='0' value='{{ line.receive_quantity }}' name='line-{{ line.id }}'/> <input class='numberinput' type='number' min='0' value='{% decimal line.receive_quantity %}' name='line-{{ line.id }}'/>
</div> </div>
</div> </div>
</td> </td>
<td>
<div class='control-group'>
<select class='select' name='status-{{ line.id }}'>
{% for code in StockStatus.RECEIVING_CODES %}
<option value="{{ code }}" {% if code|add:"0" == line.status_code|add:"0" %}selected="selected"{% endif %}>{% stock_status_text code %}</option>
{% endfor %}
</select>
</div>
</td>
<td> <td>
<button class='btn btn-default btn-remove' onClick="removeOrderRowFromOrderWizard()" id='del_item_{{ line.id }}' title='Remove line' type='button'> <button class='btn btn-default btn-remove' onClick="removeOrderRowFromOrderWizard()" id='del_item_{{ line.id }}' title='Remove line' type='button'>
<span row='line_row_{{ line.id }}' class='fas fa-trash-alt icon-red'></span> <span row='line_row_{{ line.id }}' class='fas fa-times-circle icon-red'></span>
</button> </button>
</td> </td>
</tr> </tr>

View File

@ -29,7 +29,7 @@ from . import forms as order_forms
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.helpers import DownloadFile, str2bool from InvenTree.helpers import DownloadFile, str2bool
from InvenTree.status_codes import PurchaseOrderStatus from InvenTree.status_codes import PurchaseOrderStatus, StockStatus
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -669,6 +669,20 @@ class PurchaseOrderReceive(AjaxUpdateView):
except (PurchaseOrderLineItem.DoesNotExist, ValueError): except (PurchaseOrderLineItem.DoesNotExist, ValueError):
continue continue
# Check that the StockStatus was set
status_key = 'status-{pk}'.format(pk=pk)
status = request.POST.get(status_key, StockStatus.OK)
try:
status = int(status)
except ValueError:
status = StockStatus.OK
if status in StockStatus.RECEIVING_CODES:
line.status_code = status
else:
line.status_code = StockStatus.OK
# Check that line matches the order # Check that line matches the order
if not line.order == self.order: if not line.order == self.order:
# TODO - Display a non-field error? # TODO - Display a non-field error?
@ -725,7 +739,13 @@ class PurchaseOrderReceive(AjaxUpdateView):
if not line.part: if not line.part:
continue continue
self.order.receive_line_item(line, self.destination, line.receive_quantity, self.request.user) self.order.receive_line_item(
line,
self.destination,
line.receive_quantity,
self.request.user,
status=line.status_code,
)
class OrderParts(AjaxView): class OrderParts(AjaxView):

View File

@ -28,6 +28,11 @@ def stock_status_label(key, *args, **kwargs):
return mark_safe(StockStatus.render(key, large=kwargs.get('large', False))) return mark_safe(StockStatus.render(key, large=kwargs.get('large', False)))
@register.simple_tag
def stock_status_text(key, *args, **kwargs):
return mark_safe(StockStatus.text(key))
@register.simple_tag @register.simple_tag
def build_status_label(key, *args, **kwargs): def build_status_label(key, *args, **kwargs):
""" Render a Build status label """ """ Render a Build status label """