diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html
index cd7126a801..4d2c77278c 100644
--- a/InvenTree/build/templates/build/build_base.html
+++ b/InvenTree/build/templates/build/build_base.html
@@ -151,7 +151,7 @@ src="{% static 'img/blank_image.png' %}"
{% trans "Target Date" %}
- {{ build.target_date }}
+ {% render_date build.target_date %}
{% if build.is_overdue %}
{% trans "Overdue" %}
{% endif %}
diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html
index f85ec9afa6..1e31857ba5 100644
--- a/InvenTree/build/templates/build/detail.html
+++ b/InvenTree/build/templates/build/detail.html
@@ -18,7 +18,7 @@
-
+
-
+
|
{% trans "Created" %} |
- {{ build.creation_date }} |
+ {% render_date build.creation_date %} |
|
{% trans "Target Date" %} |
{% if build.target_date %}
- {{ build.target_date }}{% if build.is_overdue %} {% endif %}
+ {% render_date build.target_date %}{% if build.is_overdue %} {% endif %}
|
{% else %}
{% trans "No target date set" %} |
@@ -142,7 +142,7 @@
|
{% trans "Completed" %} |
{% if build.completion_date %}
- {{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %} |
+ {% render_date build.completion_date %}{% if build.completed_by %}{{ build.completed_by }}{% endif %} |
{% else %}
{% trans "Build not complete" %} |
{% endif %}
diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py
index 9ef5a4d0c3..fe6ddecbba 100644
--- a/InvenTree/common/models.py
+++ b/InvenTree/common/models.py
@@ -443,12 +443,12 @@ class BaseInvenTreeSetting(models.Model):
except self.DoesNotExist:
pass
- def choices(self):
+ def choices(self, **kwargs):
"""
Return the available choices for this setting (or None if no choices are defined)
"""
- return self.__class__.get_setting_choices(self.key)
+ return self.__class__.get_setting_choices(self.key, **kwargs)
def valid_options(self):
"""
@@ -462,6 +462,33 @@ class BaseInvenTreeSetting(models.Model):
return [opt[0] for opt in choices]
+ def is_choice(self, **kwargs):
+ """
+ Check if this setting is a "choice" field
+ """
+
+ return self.__class__.get_setting_choices(self.key, **kwargs) is not None
+
+ def as_choice(self, **kwargs):
+ """
+ Render this setting as the "display" value of a choice field,
+ e.g. if the choices are:
+ [('A4', 'A4 paper'), ('A3', 'A3 paper')],
+ and the value is 'A4',
+ then display 'A4 paper'
+ """
+
+ choices = self.get_setting_choices(self.key, **kwargs)
+
+ if not choices:
+ return self.value
+
+ for value, display in choices:
+ if value == self.value:
+ return display
+
+ return self.value
+
def is_bool(self, **kwargs):
"""
Check if this setting is required to be a boolean value
@@ -1212,6 +1239,21 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
'default': False,
'validator': bool,
},
+
+ 'DATE_DISPLAY_FORMAT': {
+ 'name': _('Date Format'),
+ 'description': _('Preferred format for displaying dates'),
+ 'default': 'YYYY-MM-DD',
+ 'choices': [
+ ('YYYY-MM-DD', '2022-02-22'),
+ ('YYYY/MM/DD', '2022/22/22'),
+ ('DD-MM-YYYY', '22-02-2022'),
+ ('DD/MM/YYYY', '22/02/2022'),
+ ('MM-DD-YYYY', '02-22-2022'),
+ ('MM/DD/YYYY', '02/22/2022'),
+ ('MMM DD YYYY', 'Feb 22 2022'),
+ ]
+ }
}
class Meta:
diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html
index af1e02fd54..c188e183d0 100644
--- a/InvenTree/order/templates/order/order_base.html
+++ b/InvenTree/order/templates/order/order_base.html
@@ -141,27 +141,27 @@ src="{% static 'img/blank_image.png' %}"
|
{% trans "Created" %} |
- {{ order.creation_date }}{{ order.created_by }} |
+ {% render_date order.creation_date %}{{ order.created_by }} |
{% if order.issue_date %}
|
{% trans "Issued" %} |
- {{ order.issue_date }} |
+ {% render_date order.issue_date %} |
{% endif %}
{% if order.target_date %}
|
{% trans "Target Date" %} |
- {{ order.target_date }} |
+ {% render_date order.target_date %} |
{% endif %}
{% if order.status == PurchaseOrderStatus.COMPLETE %}
|
{% trans "Received" %} |
- {{ order.complete_date }}{{ order.received_by }} |
+ {% render_date order.complete_date %}{{ order.received_by }} |
{% endif %}
{% if order.responsible %}
diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html
index c8718d54d8..423090f917 100644
--- a/InvenTree/order/templates/order/sales_order_base.html
+++ b/InvenTree/order/templates/order/sales_order_base.html
@@ -155,13 +155,13 @@ src="{% static 'img/blank_image.png' %}"
|
{% trans "Created" %} |
- {{ order.creation_date }}{{ order.created_by }} |
+ {% render_date order.creation_date %}{{ order.created_by }} |
{% if order.target_date %}
|
{% trans "Target Date" %} |
- {{ order.target_date }} |
+ {% render_date order.target_date %} |
{% endif %}
{% if order.shipment_date %}
@@ -169,7 +169,7 @@ src="{% static 'img/blank_image.png' %}"
|
{% trans "Completed" %} |
- {{ order.shipment_date }}
+ {% render_date order.shipment_date %}
{% if order.shipped_by %}
{{ order.shipped_by }}
{% endif %}
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index 2266b39048..1cfd6c13e2 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -952,7 +952,7 @@
{% if price_history %}
var purchasepricedata = {
labels: [
- {% for line in price_history %}'{{ line.date }}',{% endfor %}
+ {% for line in price_history %}'{% render_date line.date %}',{% endfor %}
],
datasets: [{
label: '{% blocktrans %}Purchase Unit Price - {{currency}}{% endblocktrans %}',
@@ -1065,7 +1065,7 @@
{% if sale_history %}
var salepricedata = {
labels: [
- {% for line in sale_history %}'{{ line.date }}',{% endfor %}
+ {% for line in sale_history %}'{% render_date line.date %}',{% endfor %}
],
datasets: [{
label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}',
diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html
index d2505a57f7..823bb1a4f3 100644
--- a/InvenTree/part/templates/part/part_base.html
+++ b/InvenTree/part/templates/part/part_base.html
@@ -312,7 +312,7 @@
| |
{% trans "Creation Date" %} |
- {{ part.creation_date }}
+ {% render_date part.creation_date %}
{% if part.creation_user %}
{{ part.creation_user }}
{% endif %}
diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py
index 627b925e23..7f0d7ff3cc 100644
--- a/InvenTree/part/templatetags/inventree_extras.py
+++ b/InvenTree/part/templatetags/inventree_extras.py
@@ -5,6 +5,7 @@ This module provides template tags for extra functionality,
over and above the built-in Django tags.
"""
+from datetime import date
import os
import sys
@@ -43,6 +44,52 @@ def define(value, *args, **kwargs):
return value
+@register.simple_tag(takes_context=True)
+def render_date(context, date_object):
+ """
+ Renders a date according to the preference of the provided user
+
+ Note that the user preference is stored using the formatting adopted by moment.js,
+ which differs from the python formatting!
+ """
+
+ if date_object is None:
+ return None
+
+ if type(date_object) == str:
+ # If a string is passed, first convert it to a datetime
+ date_object = date.fromisoformat(date_object)
+
+ # We may have already pre-cached the date format by calling this already!
+ user_date_format = context.get('user_date_format', None)
+
+ if user_date_format is None:
+
+ user = context.get('user', None)
+
+ if user:
+ # User is specified - look for their date display preference
+ user_date_format = InvenTreeUserSetting.get_setting('DATE_DISPLAY_FORMAT', user=user)
+ else:
+ user_date_format = 'YYYY-MM-DD'
+
+ # Convert the format string to Pythonic equivalent
+ replacements = [
+ ('YYYY', '%Y'),
+ ('MMM', '%b'),
+ ('MM', '%m'),
+ ('DD', '%d'),
+ ]
+
+ for o, n in replacements:
+ user_date_format = user_date_format.replace(o, n)
+
+ # Update the context cache
+ context['user_date_format'] = user_date_format
+
+ return date_object.strftime(user_date_format)
+
+
@register.simple_tag()
def decimal(x, *args, **kwargs):
""" Simplified rendering of a decimal number """
diff --git a/InvenTree/report/templates/report/inventree_build_order_base.html b/InvenTree/report/templates/report/inventree_build_order_base.html
index 20e6a6ffd0..06d8abae65 100644
--- a/InvenTree/report/templates/report/inventree_build_order_base.html
+++ b/InvenTree/report/templates/report/inventree_build_order_base.html
@@ -120,13 +120,13 @@ content: "v{{report_revision}} - {{ date.isoformat }}";
|
{% trans "Issued" %} |
- {{ build.creation_date }} |
+ {% render_date build.creation_date %} |
{% trans "Target Date" %} |
{% if build.target_date %}
- {{ build.target_date }}
+ {% render_date build.target_date %}
{% else %}
Not specified
{% endif %}
diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html
index c52d101afb..c612abe929 100644
--- a/InvenTree/stock/templates/stock/item_base.html
+++ b/InvenTree/stock/templates/stock/item_base.html
@@ -187,7 +187,7 @@
| |
{% trans "Expiry Date" %} |
- {{ item.expiry_date }}
+ {% render_date item.expiry_date %}
{% if item.is_expired %}
{% trans "Expired" %}
{% elif item.is_stale %}
@@ -205,7 +205,7 @@
| |
{% trans "Last Stocktake" %} |
{% if item.stocktake_date %}
- {{ item.stocktake_date }} {{ item.stocktake_user }} |
+ {% render_date item.stocktake_date %} {{ item.stocktake_user }} |
{% else %}
{% trans "No stocktake performed" %} |
{% endif %}
diff --git a/InvenTree/templates/InvenTree/settings/plugin.html b/InvenTree/templates/InvenTree/settings/plugin.html
index caee7c92bf..139ce0d41a 100644
--- a/InvenTree/templates/InvenTree/settings/plugin.html
+++ b/InvenTree/templates/InvenTree/settings/plugin.html
@@ -81,7 +81,7 @@
{% endif %}
{{ plugin.author }} |
- {{ plugin.pub_date }} |
+ {% render_date plugin.pub_date %} |
{% if plugin.version %}{{ plugin.version }}{% endif %} |
{% endfor %}
diff --git a/InvenTree/templates/InvenTree/settings/plugin_settings.html b/InvenTree/templates/InvenTree/settings/plugin_settings.html
index a670d71c34..9c5fa2d7c0 100644
--- a/InvenTree/templates/InvenTree/settings/plugin_settings.html
+++ b/InvenTree/templates/InvenTree/settings/plugin_settings.html
@@ -36,7 +36,7 @@
|
{% trans "Date" %} |
- {{ plugin.pub_date }}{% include "clip.html" %} |
+ {% render_date plugin.pub_date %}{% include "clip.html" %} |
|
@@ -101,7 +101,7 @@
|
- {% trans "Commit Date" %} | {{ plugin.package.date }}{% include "clip.html" %} |
+ {% trans "Commit Date" %} | {% render_date plugin.package.date %}{% include "clip.html" %} |
|
diff --git a/InvenTree/templates/InvenTree/settings/setting.html b/InvenTree/templates/InvenTree/settings/setting.html
index 743e37bf8e..9ef6008292 100644
--- a/InvenTree/templates/InvenTree/settings/setting.html
+++ b/InvenTree/templates/InvenTree/settings/setting.html
@@ -28,7 +28,11 @@
{% if setting.value %}
+ {% if setting.is_choice %}
+ {{ setting.as_choice }}
+ {% else %}
{{ setting.value }}
+ {% endif %}
{% else %}
{% trans "No value set" %}
{% endif %}
diff --git a/InvenTree/templates/InvenTree/settings/user_display.html b/InvenTree/templates/InvenTree/settings/user_display.html
index 9f5c22f991..6432b858a3 100644
--- a/InvenTree/templates/InvenTree/settings/user_display.html
+++ b/InvenTree/templates/InvenTree/settings/user_display.html
@@ -15,6 +15,7 @@
{% include "InvenTree/settings/setting.html" with key="STICKY_HEADER" icon="fa-bars" user_setting=True %}
+ {% include "InvenTree/settings/setting.html" with key="DATE_DISPLAY_FORMAT" icon="fa-calendar-alt" user_setting=True %}
{% include "InvenTree/settings/setting.html" with key="FORMS_CLOSE_USING_ESCAPE" icon="fa-window-close" user_setting=True %}
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" user_setting=True %}
diff --git a/InvenTree/templates/about.html b/InvenTree/templates/about.html
index 34884da9d1..333185725f 100644
--- a/InvenTree/templates/about.html
+++ b/InvenTree/templates/about.html
@@ -44,7 +44,7 @@
{% if commit_date %}
|
- {% trans "Commit Date" %} | {{ commit_date }}{% include "clip.html" %} |
+ {% trans "Commit Date" %} | {% render_date commit_date %}{% include "clip.html" %} |
{% endif %}
{% endif %}
diff --git a/InvenTree/templates/js/dynamic/calendar.js b/InvenTree/templates/js/dynamic/calendar.js
index 268337bd52..0b0ccc2915 100644
--- a/InvenTree/templates/js/dynamic/calendar.js
+++ b/InvenTree/templates/js/dynamic/calendar.js
@@ -7,6 +7,7 @@
clearEvents,
endDate,
startDate,
+ renderDate,
*/
/**
@@ -32,3 +33,33 @@ function clearEvents(calendar) {
event.remove();
});
}
+
+
+/*
+ * Render the provided date in the user-specified format.
+ *
+ * The provided "date" variable is a string, nominally ISO format e.g. 2022-02-22
+ * The user-configured setting DATE_DISPLAY_FORMAT determines how the date should be displayed.
+ */
+
+function renderDate(date, options={}) {
+
+ if (!date) {
+ return null;
+ }
+
+ var fmt = user_settings.DATE_DISPLAY_FORMAT || 'YYYY-MM-DD';
+
+ if (options.showTime) {
+ fmt += ' HH:mm';
+ }
+
+ var m = moment(date);
+
+ if (m.isValid()) {
+ return m.format(fmt);
+ } else {
+ // Invalid input string, simply return provided value
+ return date;
+ }
+}
diff --git a/InvenTree/templates/js/dynamic/settings.js b/InvenTree/templates/js/dynamic/settings.js
index 133edfba20..4e7d36f72b 100644
--- a/InvenTree/templates/js/dynamic/settings.js
+++ b/InvenTree/templates/js/dynamic/settings.js
@@ -40,12 +40,15 @@ function editSetting(pk, options={}) {
url = `/api/settings/user/${pk}/`;
}
+ var reload_required = false;
+
// First, read the settings object from the server
inventreeGet(url, {}, {
success: function(response) {
if (response.choices && response.choices.length > 0) {
response.type = 'choice';
+ reload_required = true;
}
// Construct the field
@@ -89,7 +92,9 @@ function editSetting(pk, options={}) {
var setting = response.key;
- if (response.type == 'boolean') {
+ if (reload_required) {
+ location.reload();
+ } else if (response.type == 'boolean') {
var enabled = response.value.toString().toLowerCase() == 'true';
$(`#setting-value-${setting}`).prop('checked', enabled);
} else {
diff --git a/InvenTree/templates/js/translated/attachment.js b/InvenTree/templates/js/translated/attachment.js
index 44061403fa..858ca8bd84 100644
--- a/InvenTree/templates/js/translated/attachment.js
+++ b/InvenTree/templates/js/translated/attachment.js
@@ -165,6 +165,9 @@ function loadAttachmentTable(url, options) {
{
field: 'upload_date',
title: '{% trans "Upload Date" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
field: 'actions',
diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js
index fb8b870fad..1272670f7b 100644
--- a/InvenTree/templates/js/translated/build.js
+++ b/InvenTree/templates/js/translated/build.js
@@ -1961,6 +1961,9 @@ function loadBuildTable(table, options) {
field: 'creation_date',
title: '{% trans "Created" %}',
sortable: true,
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
field: 'issued_by',
@@ -1990,11 +1993,17 @@ function loadBuildTable(table, options) {
field: 'target_date',
title: '{% trans "Target Date" %}',
sortable: true,
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
field: 'completion_date',
title: '{% trans "Completion Date" %}',
sortable: true,
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
],
});
diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js
index 4a71c7d7f9..5f825c6738 100644
--- a/InvenTree/templates/js/translated/order.js
+++ b/InvenTree/templates/js/translated/order.js
@@ -923,11 +923,17 @@ function loadPurchaseOrderTable(table, options) {
field: 'creation_date',
title: '{% trans "Date" %}',
sortable: true,
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
field: 'target_date',
title: '{% trans "Target Date" %}',
sortable: true,
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
field: 'line_items',
@@ -1198,7 +1204,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
title: '{% trans "Target Date" %}',
formatter: function(value, row) {
if (row.target_date) {
- var html = row.target_date;
+ var html = renderDate(row.target_date);
if (row.overdue) {
html += ``;
@@ -1207,7 +1213,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
return html;
} else if (row.order_detail && row.order_detail.target_date) {
- return `${row.order_detail.target_date}`;
+ return `${renderDate(row.order_detail.target_date)}`;
} else {
return '-';
}
@@ -1371,16 +1377,25 @@ function loadSalesOrderTable(table, options) {
sortable: true,
field: 'creation_date',
title: '{% trans "Creation Date" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
sortable: true,
field: 'target_date',
title: '{% trans "Target Date" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
sortable: true,
field: 'shipment_date',
title: '{% trans "Shipment Date" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
},
{
sortable: true,
@@ -1532,9 +1547,9 @@ function loadSalesOrderShipmentTable(table, options={}) {
sortable: true,
formatter: function(value, row) {
if (value) {
- return value;
+ return renderDate(value);
} else {
- return '{% trans "Not shipped" %}';
+ return '{% trans "Not shipped" %}';
}
}
},
@@ -2317,7 +2332,7 @@ function loadSalesOrderLineItemTable(table, options={}) {
switchable: true,
formatter: function(value, row) {
if (row.target_date) {
- var html = row.target_date;
+ var html = renderDate(row.target_date);
if (row.overdue) {
html += ``;
@@ -2326,7 +2341,7 @@ function loadSalesOrderLineItemTable(table, options={}) {
return html;
} else if (row.order_detail && row.order_detail.target_date) {
- return `${row.order_detail.target_date}`;
+ return `${renderDate(row.order_detail.target_date)}`;
} else {
return '-';
}
diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js
index 2d84f11e4a..1ca89368dc 100644
--- a/InvenTree/templates/js/translated/stock.js
+++ b/InvenTree/templates/js/translated/stock.js
@@ -25,7 +25,6 @@
modalSetContent,
modalSetTitle,
modalSubmit,
- moment,
openModal,
printStockItemLabels,
printTestReports,
@@ -1820,6 +1819,9 @@ function loadStockTable(table, options) {
col = {
field: 'stocktake_date',
title: '{% trans "Stocktake" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
};
if (!options.params.ordering) {
@@ -1833,6 +1835,9 @@ function loadStockTable(table, options) {
title: '{% trans "Expiry Date" %}',
visible: global_settings.STOCK_ENABLE_EXPIRY,
switchable: global_settings.STOCK_ENABLE_EXPIRY,
+ formatter: function(value) {
+ return renderDate(value);
+ }
};
if (!options.params.ordering) {
@@ -1844,6 +1849,9 @@ function loadStockTable(table, options) {
col = {
field: 'updated',
title: '{% trans "Last Updated" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
};
if (!options.params.ordering) {
@@ -2649,14 +2657,7 @@ function loadStockTrackingTable(table, options) {
title: '{% trans "Date" %}',
sortable: true,
formatter: function(value) {
- var m = moment(value);
-
- if (m.isValid()) {
- var html = m.format('dddd MMMM Do YYYY'); // + ' ' + m.format('h:mm a');
- return html;
- }
-
- return '{% trans "Invalid date" %}';
+ return renderDate(value, {showTime: true});
}
});
diff --git a/InvenTree/templates/version.html b/InvenTree/templates/version.html
index b702fd85f5..7f3b774257 100644
--- a/InvenTree/templates/version.html
+++ b/InvenTree/templates/version.html
@@ -2,7 +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 %}
+{% inventree_commit_date as commit_date %}{% if commit_date %}Commit Date: {% render_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
|