diff --git a/InvenTree/company/migrations/0023_auto_20200808_0715.py b/InvenTree/company/migrations/0023_auto_20200808_0715.py new file mode 100644 index 0000000000..22097e8e2b --- /dev/null +++ b/InvenTree/company/migrations/0023_auto_20200808_0715.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.7 on 2020-08-08 07:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0022_auto_20200613_1045'), + ] + + operations = [ + migrations.AlterModelOptions( + name='company', + options={'ordering': ['name']}, + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 2179897263..a06ddd94bf 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -79,6 +79,9 @@ class Company(models.Model): is_manufacturer: boolean value, is this company a manufacturer """ + class Meta: + ordering = ['name', ] + name = models.CharField(max_length=100, blank=False, unique=True, help_text=_('Company name'), verbose_name=_('Company name')) diff --git a/InvenTree/company/templates/company/detail_stock.html b/InvenTree/company/templates/company/detail_stock.html index c33179d454..e994d5834b 100644 --- a/InvenTree/company/templates/company/detail_stock.html +++ b/InvenTree/company/templates/company/detail_stock.html @@ -26,7 +26,8 @@ }, buttons: [ '#stock-options', - ] + ], + filterKey: "companystock", }); $("#stock-export").click(function() { diff --git a/InvenTree/part/migrations/0047_auto_20200808_0715.py b/InvenTree/part/migrations/0047_auto_20200808_0715.py new file mode 100644 index 0000000000..4fc3d5a7d9 --- /dev/null +++ b/InvenTree/part/migrations/0047_auto_20200808_0715.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.7 on 2020-08-08 07:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0046_auto_20200804_0107'), + ] + + operations = [ + migrations.AlterModelOptions( + name='part', + options={'ordering': ['name'], 'verbose_name': 'Part', 'verbose_name_plural': 'Parts'}, + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 01768b4bb3..308808fbdd 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -71,8 +71,8 @@ class PartCategory(InvenTreeTree): return reverse('category-detail', kwargs={'pk': self.id}) class Meta: - verbose_name = "Part Category" - verbose_name_plural = "Part Categories" + verbose_name = _("Part Category") + verbose_name_plural = _("Part Categories") def get_parts(self, cascade=True): """ Return a queryset for all parts under this category. @@ -239,6 +239,7 @@ class Part(MPTTModel): class Meta: verbose_name = _("Part") verbose_name_plural = _("Parts") + ordering = ['name', ] class MPTTMeta: # For legacy reasons the 'variant_of' field is used to indicate the MPTT parent @@ -1490,7 +1491,7 @@ class BomItem(models.Model): pass class Meta: - verbose_name = "BOM Item" + verbose_name = _("BOM Item") # Prevent duplication of parent/child rows unique_together = ('part', 'sub_part') diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 018b588c1f..7284f8d5cd 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -477,6 +477,17 @@ class StockList(generics.ListCreateAPIView): if customer: queryset = queryset.filter(customer=customer) + # Filter if items have been sent to a customer (any customer) + sent_to_customer = params.get('sent_to_customer', None) + + if sent_to_customer is not None: + sent_to_customer = str2bool(sent_to_customer) + + if sent_to_customer: + queryset = queryset.exclude(customer=None) + else: + queryset = queryset.filter(customer=None) + # Filter by "serialized" status? serialized = params.get('serialized', None) @@ -507,6 +518,7 @@ class StockList(generics.ListCreateAPIView): if serial_number_lte is not None: queryset = queryset.filter(serial__lte=serial_number_lte) + # Filter by "in_stock" status in_stock = params.get('in_stock', None) if in_stock is not None: @@ -539,10 +551,21 @@ class StockList(generics.ListCreateAPIView): active = str2bool(active) queryset = queryset.filter(part__active=active) + # Filter by 'depleted' status + depleted = params.get('depleted', None) + + if depleted is not None: + depleted = str2bool(depleted) + + if depleted: + queryset = queryset.filter(quantity__lte=0) + else: + queryset = queryset.exclude(quantity__lte=0) + # Filter by internal part number IPN = params.get('IPN', None) - if IPN: + if IPN is not None: queryset = queryset.filter(part__IPN=IPN) # Does the client wish to filter by the Part ID? diff --git a/InvenTree/stock/templates/stock/stock_adjust.html b/InvenTree/stock/templates/stock/stock_adjust.html index a72407f735..8385fb5039 100644 --- a/InvenTree/stock/templates/stock/stock_adjust.html +++ b/InvenTree/stock/templates/stock/stock_adjust.html @@ -32,6 +32,7 @@ {% if item.error %}
{{ item.error }} diff --git a/InvenTree/templates/js/stock.html b/InvenTree/templates/js/stock.html index adaf07b4f6..11cf6a94e3 100644 --- a/InvenTree/templates/js/stock.html +++ b/InvenTree/templates/js/stock.html @@ -1,4 +1,5 @@ {% load i18n %} +{% load status_codes %} /* Stock API functions * Requires api.js to be loaded first @@ -460,12 +461,30 @@ function loadStockTable(table, options) { var html = renderLink(val, `/stock/item/${row.pk}/`); if (row.allocated) { - html += ``; + html += ``; } + if (row.customer) { + html += ``; + } else if (row.build_order) { + html += ``; + } else if (row.sales_order) { + html += ``; + } + + // Special stock status codes + + // 65 = "REJECTED" + if (row.status == 65) { + html += ``; + } // 70 = "LOST" - if (row.status == 70) { - html += ``; + else if (row.status == 70) { + html += ``; + } + + if (row.quantity <= 0) { + html += `{% trans "Depleted" %}`; } return html; diff --git a/InvenTree/templates/js/table_filters.html b/InvenTree/templates/js/table_filters.html index e2138ef6b3..9050edba6f 100644 --- a/InvenTree/templates/js/table_filters.html +++ b/InvenTree/templates/js/table_filters.html @@ -32,30 +32,35 @@ function getAvailableTableFilters(tableKey) { // Filters for the "Stock" table if (tableKey == 'stock') { return { - in_stock: { + active: { type: 'bool', - title: '{% trans "In Stock" %}', - description: '{% trans "Show items which are in stock" %}', + title: '{% trans "Active parts" %}', + description: '{% trans "Show stock for active parts" %}', + }, + allocated: { + type: 'bool', + title: '{% trans "Is allocated" %}', + description: '{% trans "Item has been alloacted" %}', }, cascade: { type: 'bool', title: '{% trans "Include sublocations" %}', description: '{% trans "Include stock in sublocations" %}', }, - active: { + depleted: { type: 'bool', - title: '{% trans "Active parts" %}', - description: '{% trans "Show stock for active parts" %}', + title: '{% trans "Depleted" %}', + description: '{% trans "Show stock items which are depleted" %}', }, - status: { - options: stockCodes, - title: '{% trans "Stock status" %}', - description: '{% trans "Stock status" %}', - }, - allocated: { + in_stock: { type: 'bool', - title: '{% trans "Is allocated" %}', - description: '{% trans "Item has been alloacted" %}', + title: '{% trans "In Stock" %}', + description: '{% trans "Show items which are in stock" %}', + }, + sent_to_customer: { + type: 'bool', + title: '{% trans "Sent to customer" %}', + description: '{% trans "Show items which have been assigned to a customer" %}', }, serialized: { type: 'bool', @@ -69,6 +74,11 @@ function getAvailableTableFilters(tableKey) { title: "{% trans "Serial number LTE" %}", description: "{% trans "Serial number less than or equal to" %}", }, + status: { + options: stockCodes, + title: '{% trans "Stock status" %}', + description: '{% trans "Stock status" %}', + }, }; }