mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
1519a4f882
@ -667,6 +667,7 @@ LANGUAGES = [
|
||||
('en', _('English')),
|
||||
('es', _('Spanish')),
|
||||
('es-mx', _('Spanish (Mexican)')),
|
||||
('fa', _('Farsi / Persian')),
|
||||
('fr', _('French')),
|
||||
('he', _('Hebrew')),
|
||||
('hu', _('Hungarian')),
|
||||
|
@ -255,6 +255,9 @@ class StockHistoryCode(StatusCode):
|
||||
# Stock merging operations
|
||||
MERGED_STOCK_ITEMS = 45
|
||||
|
||||
# Convert stock item to variant
|
||||
CONVERTED_TO_VARIANT = 48
|
||||
|
||||
# Build order codes
|
||||
BUILD_OUTPUT_CREATED = 50
|
||||
BUILD_OUTPUT_COMPLETED = 55
|
||||
@ -294,6 +297,8 @@ class StockHistoryCode(StatusCode):
|
||||
|
||||
MERGED_STOCK_ITEMS: _('Merged stock items'),
|
||||
|
||||
CONVERTED_TO_VARIANT: _('Converted to variant'),
|
||||
|
||||
SENT_TO_CUSTOMER: _('Sent to customer'),
|
||||
RETURNED_FROM_CUSTOMER: _('Returned from customer'),
|
||||
|
||||
|
@ -12,11 +12,14 @@ import common.models
|
||||
INVENTREE_SW_VERSION = "0.7.0 dev"
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 38
|
||||
INVENTREE_API_VERSION = 39
|
||||
|
||||
"""
|
||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||
|
||||
v39 -> 2022-04-18
|
||||
- Adds ability to filter StockItem list by "has_batch" parameter
|
||||
|
||||
v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828
|
||||
- Adds the ability to include stock test results for "installed items"
|
||||
|
||||
|
@ -238,7 +238,7 @@
|
||||
});
|
||||
|
||||
{% if company.is_customer %}
|
||||
onPanelLoad('panel-sales-orders', function() {
|
||||
onPanelLoad('sales-orders', function() {
|
||||
loadSalesOrderTable("#sales-order-table", {
|
||||
url: "{% url 'api-so-list' %}",
|
||||
params: {
|
||||
|
BIN
InvenTree/locale/fa/LC_MESSAGES/django.mo
Normal file
BIN
InvenTree/locale/fa/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
7845
InvenTree/locale/fa/LC_MESSAGES/django.po
Normal file
7845
InvenTree/locale/fa/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -410,6 +410,20 @@ class StockFilter(rest_filters.FilterSet):
|
||||
|
||||
return queryset
|
||||
|
||||
has_batch = rest_filters.BooleanFilter(label='Has batch code', method='filter_has_batch')
|
||||
|
||||
def filter_has_batch(self, queryset, name, value):
|
||||
"""
|
||||
Filter by whether the StockItem has a batch code (or not)
|
||||
"""
|
||||
|
||||
if str2bool(value):
|
||||
queryset = queryset.exclude(batch=None)
|
||||
else:
|
||||
queryset = queryset.filter(batch=None)
|
||||
|
||||
return queryset
|
||||
|
||||
installed = rest_filters.BooleanFilter(label='Installed in other stock item', method='filter_installed')
|
||||
|
||||
def filter_installed(self, queryset, name, value):
|
||||
@ -1220,6 +1234,15 @@ class StockTrackingList(generics.ListAPIView):
|
||||
if not deltas:
|
||||
deltas = {}
|
||||
|
||||
# Add part detail
|
||||
if 'part' in deltas:
|
||||
try:
|
||||
part = Part.objects.get(pk=deltas['part'])
|
||||
serializer = PartBriefSerializer(part)
|
||||
deltas['part_detail'] = serializer.data
|
||||
except:
|
||||
pass
|
||||
|
||||
# Add location detail
|
||||
if 'location' in deltas:
|
||||
try:
|
||||
|
@ -718,6 +718,33 @@ class StockItem(MPTTModel):
|
||||
help_text=_('Select Owner'),
|
||||
related_name='stock_items')
|
||||
|
||||
@transaction.atomic
|
||||
def convert_to_variant(self, variant, user, notes=None):
|
||||
"""
|
||||
Convert this StockItem instance to a "variant",
|
||||
i.e. change the "part" reference field
|
||||
"""
|
||||
|
||||
if not variant:
|
||||
# Ignore null values
|
||||
return
|
||||
|
||||
if variant == self.part:
|
||||
# Variant is the same as the current part
|
||||
return
|
||||
|
||||
self.part = variant
|
||||
self.save()
|
||||
|
||||
self.add_tracking_entry(
|
||||
StockHistoryCode.CONVERTED_TO_VARIANT,
|
||||
user,
|
||||
deltas={
|
||||
'part': variant.pk,
|
||||
},
|
||||
notes=_('Converted to part') + ': ' + variant.full_name,
|
||||
)
|
||||
|
||||
def get_item_owner(self):
|
||||
"""
|
||||
Return the closest "owner" for this StockItem.
|
||||
|
@ -26,11 +26,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class='panel-content'>
|
||||
<div id='table-toolbar'>
|
||||
<div id='tracking-table-toolbar'>
|
||||
<div class='btn-group'>
|
||||
{% include "filter_list.html" with id="stocktracking" %}
|
||||
</div>
|
||||
</div>
|
||||
<table class='table table-condensed table-striped' id='track-table' data-toolbar='#table-toolbar'>
|
||||
<table class='table table-condensed table-striped' id='track-table' data-toolbar='#tracking-table-toolbar'>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -342,7 +343,6 @@
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
loadStockTrackingTable($("#track-table"), {
|
||||
params: {
|
||||
ordering: '-date',
|
||||
|
@ -644,6 +644,16 @@ class StockItemConvert(AjaxUpdateView):
|
||||
|
||||
return form
|
||||
|
||||
def save(self, obj, form):
|
||||
|
||||
stock_item = self.get_object()
|
||||
|
||||
variant = form.cleaned_data.get('part', None)
|
||||
|
||||
stock_item.convert_to_variant(variant, user=self.request.user)
|
||||
|
||||
return stock_item
|
||||
|
||||
|
||||
class StockLocationCreate(AjaxCreateView):
|
||||
"""
|
||||
|
@ -99,14 +99,22 @@ function renderStockItem(name, data, parameters={}, options={}) {
|
||||
|
||||
var stock_detail = '';
|
||||
|
||||
if (data.serial && data.quantity == 1) {
|
||||
stock_detail = `{% trans "Serial Number" %}: ${data.serial}`;
|
||||
} else if (data.quantity == 0) {
|
||||
if (data.quantity == 0) {
|
||||
stock_detail = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock"% }</span>`;
|
||||
} else {
|
||||
stock_detail = `{% trans "Quantity" %}: ${data.quantity}`;
|
||||
if (data.serial && data.quantity == 1) {
|
||||
stock_detail = `{% trans "Serial Number" %}: ${data.serial}`;
|
||||
} else {
|
||||
stock_detail = `{% trans "Quantity" %}: ${data.quantity}`;
|
||||
}
|
||||
|
||||
if (data.batch != null) {
|
||||
stock_detail += ` - <small>{% trans "Batch" %}: ${data.batch}</small>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var html = `
|
||||
<span>
|
||||
${part_detail}
|
||||
|
@ -293,6 +293,7 @@ function categoryFields() {
|
||||
return {
|
||||
parent: {
|
||||
help_text: '{% trans "Parent part category" %}',
|
||||
required: false,
|
||||
},
|
||||
name: {},
|
||||
description: {},
|
||||
|
@ -107,6 +107,7 @@ function stockLocationFields(options={}) {
|
||||
var fields = {
|
||||
parent: {
|
||||
help_text: '{% trans "Parent stock location" %}',
|
||||
required: false,
|
||||
},
|
||||
name: {},
|
||||
description: {},
|
||||
@ -963,6 +964,10 @@ function adjustStock(action, items, options={}) {
|
||||
quantity = `#${item.serial}`;
|
||||
}
|
||||
|
||||
if (item.batch != null) {
|
||||
quantity += ` - <small>{% trans "Batch" %}: ${item.batch}</small>`;
|
||||
}
|
||||
|
||||
var actionInput = '';
|
||||
|
||||
if (actionTitle != null) {
|
||||
@ -2314,6 +2319,23 @@ function loadStockTrackingTable(table, options) {
|
||||
|
||||
var cols = [];
|
||||
|
||||
var filterTarget = '#filter-list-stocktracking';
|
||||
|
||||
var filterKey = 'stocktracking';
|
||||
|
||||
var filters = loadTableFilters(filterKey);
|
||||
|
||||
var params = options.params;
|
||||
|
||||
var original = {};
|
||||
|
||||
for (var k in params) {
|
||||
original[k] = params[k];
|
||||
filters[k] = params[k];
|
||||
}
|
||||
|
||||
setupFilterList(filterKey, table, filterTarget);
|
||||
|
||||
// Date
|
||||
cols.push({
|
||||
field: 'date',
|
||||
@ -2351,6 +2373,19 @@ function loadStockTrackingTable(table, options) {
|
||||
return html;
|
||||
}
|
||||
|
||||
// Part information
|
||||
if (details.part) {
|
||||
html += `<tr><th>{% trans "Part" %}</th><td>`;
|
||||
|
||||
if (details.part_detail) {
|
||||
html += renderLink(details.part_detail.full_name, `/part/${details.part}/`);
|
||||
} else {
|
||||
html += `{% trans "Part information unavailable" %}`;
|
||||
}
|
||||
|
||||
html += `</td></tr>`;
|
||||
}
|
||||
|
||||
// Location information
|
||||
if (details.location) {
|
||||
|
||||
@ -2488,27 +2523,10 @@ function loadStockTrackingTable(table, options) {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
// 2021-05-11 - Ability to edit or delete StockItemTracking entries is now removed
|
||||
cols.push({
|
||||
sortable: false,
|
||||
formatter: function(value, row, index, field) {
|
||||
// Manually created entries can be edited or deleted
|
||||
if (false && !row.system) {
|
||||
var bEdit = "<button title='{% trans 'Edit tracking entry' %}' class='btn btn-entry-edit btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
|
||||
var bDel = "<button title='{% trans 'Delete tracking entry' %}' class='btn btn-entry-delete btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
|
||||
|
||||
return "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
table.inventreeTable({
|
||||
method: 'get',
|
||||
queryParams: options.params,
|
||||
queryParams: filters,
|
||||
original: original,
|
||||
columns: cols,
|
||||
url: options.url,
|
||||
});
|
||||
|
@ -234,6 +234,10 @@ function getAvailableTableFilters(tableKey) {
|
||||
title: '{% trans "Stock status" %}',
|
||||
description: '{% trans "Stock status" %}',
|
||||
},
|
||||
has_batch: {
|
||||
title: '{% trans "Has batch code" %}',
|
||||
type: 'bool',
|
||||
},
|
||||
batch: {
|
||||
title: '{% trans "Batch" %}',
|
||||
description: '{% trans "Batch code" %}',
|
||||
|
Loading…
Reference in New Issue
Block a user