2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 03:00:54 +00:00

Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters
2020-08-08 09:52:48 +10:00
15 changed files with 144 additions and 51 deletions

View File

@ -46,6 +46,18 @@ class AssignStockItemToCustomerForm(HelperForm):
]
class ReturnStockItemForm(HelperForm):
"""
Form for manually returning a StockItem into stock
"""
class Meta:
model = StockItem
fields = [
'location',
]
class EditStockItemTestResultForm(HelperForm):
"""
Form for creating / editing a StockItemTestResult object.

View File

@ -0,0 +1,19 @@
# Generated by Django 3.0.7 on 2020-08-07 23:44
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0047_auto_20200605_0932'),
]
operations = [
migrations.AlterField(
model_name='stockitem',
name='status',
field=models.PositiveIntegerField(choices=[(10, 'OK'), (50, 'Attention needed'), (55, 'Damaged'), (60, 'Destroyed'), (70, 'Lost'), (65, 'Rejected'), (85, 'Returned')], default=10, validators=[django.core.validators.MinValueValidator(0)]),
),
]

View File

@ -140,6 +140,7 @@ class StockItem(MPTTModel):
sales_order=None,
build_order=None,
belongs_to=None,
customer=None,
status__in=StockStatus.AVAILABLE_CODES
)
@ -219,12 +220,6 @@ class StockItem(MPTTModel):
super().clean()
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",
'status': 'Status cannot be marked as ASSIGNED_TO_OTHER_ITEM if the belongs_to field is not set',
})
try:
if self.part.trackable:
# Trackable parts must have integer values for quantity field!
@ -477,7 +472,6 @@ class StockItem(MPTTModel):
# Update StockItem fields with new information
item.sales_order = order
item.status = StockStatus.SHIPPED
item.customer = customer
item.location = None
@ -495,6 +489,23 @@ class StockItem(MPTTModel):
# Return the reference to the stock item
return item
def returnFromCustomer(self, location, user=None):
"""
Return stock item from customer, back into the specified location.
"""
self.addTransactionNote(
_("Returned from customer") + " " + self.customer.name,
user,
notes=_("Returned to location") + " " + location.name,
system=True
)
self.customer = None
self.location = location
self.save()
# If stock item is incoming, an (optional) ETA field
# expected_arrival = models.DateField(null=True, blank=True)
@ -599,6 +610,10 @@ class StockItem(MPTTModel):
if self.build_order is not None:
return False
# Not 'in stock' if it has been assigned to a customer
if self.customer is not None:
return False
# Not 'in stock' if the status code makes it unavailable
if self.status in StockStatus.UNAVAILABLE_CODES:
return False

View File

@ -86,30 +86,34 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
{% endif %}
</ul>
</div>
{% if item.in_stock %}
<!-- Stock adjustment menu -->
<div class='dropdown dropdown-buttons'>
<button id='stock-options' title='{% trans "Stock adjustment actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
{% if item.in_stock %}
{% if not item.serialized %}
<li><a href='#' id='stock-count' title='{% trans "Count stock" %}'><span class='fas fa-clipboard-list'></span> {% trans "Count stock" %}</a></li>
<li><a href='#' id='stock-add' title='{% trans "Add stock" %}'><span class='fas fa-plus-circle icon-green'></span> {% trans "Add stock" %}</a></li>
<li><a href='#' id='stock-remove' title='{% trans "Remove stock" %}'><span class='fas fa-minus-circle icon-red'></span> {% trans "Remove stock" %}</a></li>
{% endif %}
<li><a href='#' id='stock-move' title='{% trans "Transfer stock" %}'><span class='fas fa-exchange-alt icon-blue'></span> {% trans "Transfer stock" %}</a></li>
</ul>
</div>
{% endif %}
<!-- Edit stock item -->
<div class='dropdown dropdown-buttons'>
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
{% if item.part.trackable and not item.serialized %}
<li><a href='#' id='stock-serialize' title='{% trans "Serialize stock" %}'><span class='fas fa-hashtag'></span> {% trans "Serialize stock" %}</a> </li>
{% endif %}
{% endif %}
{% if item.part.salable and not item.customer %}
<li><a href='#' id='stock-assign-to-customer' title='{% trans "Assign to customer" %}'><span class='fas fa-user-tie'></span> {% trans "Assign to customer" %}</a></li>
{% endif %}
{% if item.customer %}
<li><a href='#' id='stock-return-from-customer' title='{% trans "Return to stock" %}'><span class='fas fa-undo'></span> {% trans "Return to stock" %}</a></li>
{% endif %}
</ul>
</div>
<!-- Edit stock item -->
<div class='dropdown dropdown-buttons'>
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'>
{% if item.part.has_variants %}
<li><a href='#' id='stock-convert' title='{% trans "Convert to variant" %}'><span class='fas fa-screwdriver'></span> {% trans "Convert to variant" %}</a></li>
{% endif %}
@ -157,7 +161,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
<tr>
<td><span class='fas fa-user-tie'></span></td>
<td>{% trans "Customer" %}</td>
<td><a href="{% url 'company-detail' item.customer.id %}">{{ item.customer.name }}</a></td>
<td><a href="{% url 'company-detail-assigned-stock' item.customer.id %}">{{ item.customer.name }}</a></td>
</tr>
{% endif %}
{% if item.belongs_to %}
@ -349,7 +353,6 @@ $("#unlink-barcode").click(function() {
{% if item.in_stock %}
{% if item.part.salable %}
$("#stock-assign-to-customer").click(function() {
launchModalForm("{% url 'stock-item-assign' item.id %}",
{
@ -357,7 +360,6 @@ $("#stock-assign-to-customer").click(function() {
}
);
});
{% endif %}
function itemAdjust(action) {
launchModalForm("/stock/adjust/",
@ -398,6 +400,16 @@ $('#stock-add').click(function() {
itemAdjust('add');
});
{% else %}
$("#stock-return-from-customer").click(function() {
launchModalForm("{% url 'stock-item-return' item.id %}",
{
reload: true,
}
);
});
{% endif %}
$("#stock-delete").click(function () {

View File

@ -24,6 +24,7 @@ stock_item_detail_urls = [
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'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),

View File

@ -260,6 +260,41 @@ class StockItemAssignToCustomer(AjaxUpdateView):
return self.renderJsonResponse(request, self.get_form(), data)
class StockItemReturnToStock(AjaxUpdateView):
"""
View for returning a stock item (which is assigned to a customer) to stock.
"""
model = StockItem
ajax_form_title = _("Return to Stock")
context_object_name = "item"
form_class = StockForms.ReturnStockItemForm
def post(self, request, *args, **kwargs):
location = request.POST.get('location', None)
if location:
try:
location = StockLocation.objects.get(pk=location)
except (ValueError, StockLocation.DoesNotExist):
location = None
if location:
stock_item = self.get_object()
stock_item.returnFromCustomer(location, request.user)
else:
raise ValidationError({'location': _("Specify a valid location")})
data = {
'form_valid': True,
'success': _("Stock item returned from customer")
}
return self.renderJsonResponse(request, self.get_form(), data)
class StockItemDeleteTestData(AjaxUpdateView):
"""
View for deleting all test data