diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index 3f9c2d6cec..a3b23dd07d 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -88,6 +88,11 @@ DEBUG = _is_true(get_setting(
CONFIG.get('debug', True)
))
+DOCKER = _is_true(get_setting(
+ 'INVENTREE_DOCKER',
+ False
+))
+
# Configure logging settings
log_level = get_setting(
'INVENTREE_LOG_LEVEL',
diff --git a/InvenTree/InvenTree/static/script/inventree/inventree.js b/InvenTree/InvenTree/static/script/inventree/inventree.js
index 4b43b342af..1a6fdec47a 100644
--- a/InvenTree/InvenTree/static/script/inventree/inventree.js
+++ b/InvenTree/InvenTree/static/script/inventree/inventree.js
@@ -12,7 +12,7 @@ function attachClipboard(selector, containerselector, textElement) {
return document.getElementById(textElement).textContent;
}
} else {
- text = function() {
+ text = function(trigger) {
var content = trigger.parentElement.parentElement.textContent;return content.trim();
}
}
@@ -22,7 +22,6 @@ function attachClipboard(selector, containerselector, textElement) {
text: text,
container: containerselector
});
- console.log(cis);
}
@@ -81,7 +80,6 @@ function inventreeDocReady() {
attachClipboard('.clip-btn');
attachClipboard('.clip-btn', 'modal-about'); // modals
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text'); // version-text
-
}
function isFileTransfer(transfer) {
diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py
index 6018f64cef..669a5e8212 100644
--- a/InvenTree/common/views.py
+++ b/InvenTree/common/views.py
@@ -459,8 +459,8 @@ class FileManagementFormView(MultiStepFormView):
if guess:
n = list(self.column_selections.values()).count(self.column_selections[col])
- if n > 1:
- duplicates.append(col)
+ if n > 1 and self.column_selections[col] not in duplicates:
+ duplicates.append(self.column_selections[col])
# Store extra context data
self.extra_context_data = {
diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py
index 4519f8a2a9..1e7b20e5a1 100644
--- a/InvenTree/order/admin.py
+++ b/InvenTree/order/admin.py
@@ -13,6 +13,10 @@ from .models import SalesOrder, SalesOrderLineItem
from .models import SalesOrderAllocation
+class PurchaseOrderLineItemInlineAdmin(admin.StackedInline):
+ model = PurchaseOrderLineItem
+
+
class PurchaseOrderAdmin(ImportExportModelAdmin):
list_display = (
@@ -29,6 +33,10 @@ class PurchaseOrderAdmin(ImportExportModelAdmin):
'description',
]
+ inlines = [
+ PurchaseOrderLineItemInlineAdmin
+ ]
+
class SalesOrderAdmin(ImportExportModelAdmin):
diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py
index 5305038b4f..fb169e0536 100644
--- a/InvenTree/order/models.py
+++ b/InvenTree/order/models.py
@@ -826,6 +826,9 @@ class SalesOrderAllocation(models.Model):
else:
return ""
+ def get_po(self):
+ return self.item.purchase_order
+
def complete_allocation(self, user):
"""
Complete this allocation (called when the parent SalesOrder is marked as "shipped"):
diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py
index 062e8986b2..6091140313 100644
--- a/InvenTree/order/serializers.py
+++ b/InvenTree/order/serializers.py
@@ -235,6 +235,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
location_path = serializers.CharField(source='get_location_path')
location_id = serializers.IntegerField(source='get_location')
serial = serializers.CharField(source='get_serial')
+ po = serializers.CharField(source='get_po')
quantity = serializers.FloatField()
class Meta:
@@ -247,6 +248,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
'quantity',
'location_id',
'location_path',
+ 'po',
'item',
]
diff --git a/InvenTree/order/templates/order/order_wizard/match_fields.html b/InvenTree/order/templates/order/order_wizard/match_fields.html
index 4ff7b6a963..cd81142341 100644
--- a/InvenTree/order/templates/order/order_wizard/match_fields.html
+++ b/InvenTree/order/templates/order/order_wizard/match_fields.html
@@ -55,7 +55,7 @@
{{ col }}
{% for duplicate in duplicates %}
- {% if duplicate == col.name %}
+ {% if duplicate == col.value %}
{% trans "Duplicate selection" %}
diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html
index 72b7d63911..a90e61bff9 100644
--- a/InvenTree/order/templates/order/sales_order_detail.html
+++ b/InvenTree/order/templates/order/sales_order_detail.html
@@ -87,6 +87,9 @@ function showAllocationSubTable(index, row, element) {
return renderLink(row.location_path, `/stock/location/${row.location_id}/`);
},
},
+ {
+ field: 'po'
+ },
{
field: 'buttons',
title: '{% trans "Actions" %}',
@@ -159,9 +162,12 @@ function showFulfilledSubTable(index, row, element) {
text = `{% trans "Quantity" %}: ${row.quantity}`;
}
- return renderLink(text, `/stock/item/${row.pk}/`);
+ return renderLink(text, `/stock/item/${row.pk}/`);
},
- }
+ },
+ {
+ field: 'po'
+ },
],
});
}
@@ -271,6 +277,25 @@ $("#so-lines-table").inventreeTable({
field: 'notes',
title: '{% trans "Notes" %}',
},
+ {
+ field: 'po',
+ title: '{% trans "PO" %}',
+ formatter: function(value, row, index, field) {
+ var po_name = "";
+ if (row.allocated) {
+ row.allocations.forEach(function(allocation) {
+ if (allocation.po != po_name) {
+ if (po_name) {
+ po_name = "-";
+ } else {
+ po_name = allocation.po
+ }
+ }
+ })
+ }
+ return `` + po_name + ` `;
+ }
+ },
{% if order.status == SalesOrderStatus.PENDING %}
{
field: 'buttons',
diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py
index cf79746f0d..c8ec42d3e7 100644
--- a/InvenTree/order/views.py
+++ b/InvenTree/order/views.py
@@ -90,7 +90,7 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
""" Detail view for a SalesOrder object """
context_object_name = 'order'
- queryset = SalesOrder.objects.all().prefetch_related('lines')
+ queryset = SalesOrder.objects.all().prefetch_related('lines__allocations__item__purchase_order')
template_name = 'order/sales_order_detail.html'
diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py
index 6ac34f9d5e..e73dfe88c4 100644
--- a/InvenTree/part/templatetags/inventree_extras.py
+++ b/InvenTree/part/templatetags/inventree_extras.py
@@ -1,8 +1,14 @@
+# -*- coding: utf-8 -*-
+
""" This module provides template tags for extra functionality
over and above the built-in Django tags.
"""
+
import os
+from django.utils.translation import ugettext_lazy as _
+from django.conf import settings as djangosettings
+
from django import template
from django.urls import reverse
from django.utils.safestring import mark_safe
@@ -68,6 +74,33 @@ def part_allocation_count(build, part, *args, **kwargs):
return InvenTree.helpers.decimal2string(build.getAllocatedQuantity(part))
+@register.simple_tag()
+def inventree_in_debug_mode(*args, **kwargs):
+ """ Return True if the server is running in DEBUG mode """
+
+ return djangosettings.DEBUG
+
+
+@register.simple_tag()
+def inventree_docker_mode(*args, **kwargs):
+ """ Return True if the server is running as a Docker image """
+
+ return djangosettings.DOCKER
+
+
+@register.simple_tag()
+def inventree_db_engine(*args, **kwargs):
+ """ Return the InvenTree database backend e.g. 'postgresql' """
+
+ db = djangosettings.DATABASES['default']
+
+ engine = db.get('ENGINE', _('Unknown database'))
+
+ engine = engine.replace('django.db.backends.', '')
+
+ return engine
+
+
@register.simple_tag()
def inventree_instance_name(*args, **kwargs):
""" Return the InstanceName associated with the current database """
diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py
index 28123ebc41..88f8dd081c 100644
--- a/InvenTree/stock/models.py
+++ b/InvenTree/stock/models.py
@@ -1370,6 +1370,12 @@ class StockItem(MPTTModel):
if self.location:
s += ' @ {loc}'.format(loc=self.location.name)
+ if self.purchase_order:
+ s += " ({pre}{po})".format(
+ pre=helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
+ po=self.purchase_order,
+ )
+
return s
@transaction.atomic
diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js
index b621caab80..f447fdce72 100644
--- a/InvenTree/templates/js/modals.js
+++ b/InvenTree/templates/js/modals.js
@@ -89,6 +89,15 @@ function setFieldOptions(fieldName, optionList, options={}) {
}
+function clearFieldOptions(fieldName) {
+ /**
+ * Clear (emtpy) the options list for a particular field
+ */
+
+ setFieldOptions(fieldName, []);
+}
+
+
function reloadFieldOptions(fieldName, options) {
/* Reload the options for a given field,
* using an AJAX request.
diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js
index a0601aeb13..8f06d403ee 100644
--- a/InvenTree/templates/js/stock.js
+++ b/InvenTree/templates/js/stock.js
@@ -1218,6 +1218,17 @@ function createNewStockItem(options) {
field: 'part',
action: function(value) {
+ if (!value) {
+ // No part chosen
+
+ clearFieldOptions('supplier_part');
+ enableField('serial_numbers', false);
+ enableField('purchase_price_0', false);
+ enableField('purchase_price_1', false);
+
+ return;
+ }
+
// Reload options for supplier part
reloadFieldOptions(
'supplier_part',
@@ -1243,6 +1254,9 @@ function createNewStockItem(options) {
enableField('serial_numbers', response.trackable);
clearField('serial_numbers');
+ enableField('purchase_price_0', response.purchaseable);
+ enableField('purchase_price_1', response.purchaseable);
+
// Populate the expiry date
if (response.default_expiry <= 0) {
// No expiry date
diff --git a/InvenTree/templates/stats.html b/InvenTree/templates/stats.html
index eff9c4504f..403030644a 100644
--- a/InvenTree/templates/stats.html
+++ b/InvenTree/templates/stats.html
@@ -13,6 +13,27 @@
| {% trans "Instance Name" %} |
{% inventree_instance_name %} |
+
+ |
+ {% trans "Database" %} |
+ {% inventree_db_engine %} |
+
+ {% inventree_in_debug_mode as debug_mode %}
+ {% if debug_mode %}
+
+ |
+ {% trans "Debug Mode" %} |
+ {% trans "Server is running in debug mode" %} |
+
+ {% endif %}
+ {% inventree_docker_mode as docker_mode %}
+ {% if docker_mode %}
+
+ |
+ {% trans "Docker Mode" %} |
+ {% trans "Server is deployed using docker" %} |
+
+ {% endif %}
{% if user.is_staff %}
|
diff --git a/InvenTree/templates/version.html b/InvenTree/templates/version.html
index c8ec6862b6..b702fd85f5 100644
--- a/InvenTree/templates/version.html
+++ b/InvenTree/templates/version.html
@@ -2,4 +2,7 @@
InvenTree-Version: {% inventree_version %}
Django Version: {% django_version %}
{% inventree_commit_hash as hash %}{% if hash %}Commit Hash: {{ hash }}{% endif %}
-{% inventree_commit_date as commit_date %}{% if commit_date %}Commit Date: {{ commit_date }}{% endif %}
\ No newline at end of file
+{% inventree_commit_date as commit_date %}{% if commit_date %}Commit Date: {{ commit_date }}{% endif %}
+Database: {% inventree_db_engine %}
+Debug-Mode: {% inventree_in_debug_mode %}
+Deployed using Docker: {% inventree_docker_mode %}
\ No newline at end of file
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 3e0a7e1230..ea70d9f994 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -14,6 +14,7 @@ ENV INVENTREE_REPO="${repository}"
ENV INVENTREE_BRANCH="${branch}"
ENV INVENTREE_LOG_LEVEL="INFO"
+ENV INVENTREE_DOCKER="true"
# InvenTree paths
ENV INVENTREE_SRC_DIR="${INVENTREE_HOME}/src"