mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-23 09:35:30 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
@@ -49,12 +49,14 @@ jobs:
|
|||||||
# Build the development docker image (using docker-compose.yml)
|
# Build the development docker image (using docker-compose.yml)
|
||||||
run: |
|
run: |
|
||||||
docker-compose build
|
docker-compose build
|
||||||
- name: Run Unit Tests
|
- name: Update Docker Image
|
||||||
run: |
|
run: |
|
||||||
docker-compose run inventree-dev-server invoke update
|
docker-compose run inventree-dev-server invoke update
|
||||||
docker-compose run inventree-dev-server invoke setup-dev
|
docker-compose run inventree-dev-server invoke setup-dev
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
docker-compose run inventree-dev-server invoke wait
|
docker-compose run inventree-dev-server invoke wait
|
||||||
|
- name: Run Unit Tests
|
||||||
|
run: |
|
||||||
docker-compose run inventree-dev-server invoke test
|
docker-compose run inventree-dev-server invoke test
|
||||||
docker-compose down
|
docker-compose down
|
||||||
- name: Check Data Directory
|
- name: Check Data Directory
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import shutil
|
|||||||
import string
|
import string
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
@@ -61,6 +59,8 @@ def get_config_file(create=True) -> Path:
|
|||||||
def load_config_data() -> map:
|
def load_config_data() -> map:
|
||||||
"""Load configuration data from the config file."""
|
"""Load configuration data from the config file."""
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
cfg_file = get_config_file()
|
cfg_file = get_config_file()
|
||||||
|
|
||||||
with open(cfg_file, 'r') as cfg:
|
with open(cfg_file, 'r') as cfg:
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ if cache_host: # pragma: no cover
|
|||||||
|
|
||||||
# database user sessions
|
# database user sessions
|
||||||
SESSION_ENGINE = 'user_sessions.backends.db'
|
SESSION_ENGINE = 'user_sessions.backends.db'
|
||||||
LOGOUT_REDIRECT_URL = 'index'
|
LOGOUT_REDIRECT_URL = get_setting('INVENTREE_LOGOUT_REDIRECT_URL', 'logout_redirect_url', 'index')
|
||||||
SILENCED_SYSTEM_CHECKS = [
|
SILENCED_SYSTEM_CHECKS = [
|
||||||
'admin.E410',
|
'admin.E410',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -777,6 +777,7 @@ class TestSettings(helpers.InvenTreeTestCase):
|
|||||||
"""Test if install of plugins on startup works."""
|
"""Test if install of plugins on startup works."""
|
||||||
from plugin import registry
|
from plugin import registry
|
||||||
|
|
||||||
|
if not settings.DOCKER:
|
||||||
# Check an install run
|
# Check an install run
|
||||||
response = registry.install_plugin_file()
|
response = registry.install_plugin_file()
|
||||||
self.assertEqual(response, 'first_run')
|
self.assertEqual(response, 'first_run')
|
||||||
|
|||||||
@@ -258,7 +258,12 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
"""
|
"""
|
||||||
setting = cls.get_setting_definition(key, **kwargs)
|
setting = cls.get_setting_definition(key, **kwargs)
|
||||||
|
|
||||||
return setting.get('default', '')
|
default = setting.get('default', '')
|
||||||
|
|
||||||
|
if callable(default):
|
||||||
|
return default()
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_setting_choices(cls, key, **kwargs):
|
def get_setting_choices(cls, key, **kwargs):
|
||||||
@@ -1100,6 +1105,27 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'PRICING_PURCHASE_HISTORY_OVERRIDES_SUPPLIER': {
|
||||||
|
'name': _('Purchase History Override'),
|
||||||
|
'description': _('Historical purchase order pricing overrides supplier price breaks'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'PRICING_USE_VARIANT_PRICING': {
|
||||||
|
'name': _('Use Variant Pricing'),
|
||||||
|
'description': _('Include variant pricing in overall pricing calculations'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'PRICING_ACTIVE_VARIANTS': {
|
||||||
|
'name': _('Active Variants Only'),
|
||||||
|
'description': _('Only use active variant parts for calculating variant pricing'),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
'PRICING_UPDATE_DAYS': {
|
'PRICING_UPDATE_DAYS': {
|
||||||
'name': _('Pricing Rebuild Time'),
|
'name': _('Pricing Rebuild Time'),
|
||||||
'description': _('Number of days before part pricing is automatically updated'),
|
'description': _('Number of days before part pricing is automatically updated'),
|
||||||
@@ -1345,7 +1371,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'PLUGIN_ON_STARTUP': {
|
'PLUGIN_ON_STARTUP': {
|
||||||
'name': _('Check plugins on startup'),
|
'name': _('Check plugins on startup'),
|
||||||
'description': _('Check that all plugins are installed on startup - enable in container environments'),
|
'description': _('Check that all plugins are installed on startup - enable in container environments'),
|
||||||
'default': False,
|
'default': settings.DOCKER,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
'requires_restart': True,
|
'requires_restart': True,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ class SupplierPartAdmin(ImportExportModelAdmin):
|
|||||||
list_display = ('part', 'supplier', 'SKU')
|
list_display = ('part', 'supplier', 'SKU')
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
'company__name',
|
'supplier__name',
|
||||||
'part__name',
|
'part__name',
|
||||||
'MPN',
|
'manufacturer_part__MPN',
|
||||||
'SKU',
|
'SKU',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -171,6 +171,12 @@ login_default_protocol: http
|
|||||||
remote_login_enabled: False
|
remote_login_enabled: False
|
||||||
remote_login_header: HTTP_REMOTE_USER
|
remote_login_header: HTTP_REMOTE_USER
|
||||||
|
|
||||||
|
# Logout redirect configuration
|
||||||
|
# This setting may be required if using remote / proxy login to redirect requests
|
||||||
|
# during the logout process (default is 'index'). Please read the docs for more details
|
||||||
|
# https://docs.djangoproject.com/en/stable/ref/settings/#logout-redirect-url
|
||||||
|
#logout_redirect_url: 'index'
|
||||||
|
|
||||||
# Permit custom authentication backends
|
# Permit custom authentication backends
|
||||||
#authentication_backends:
|
#authentication_backends:
|
||||||
# - 'django.contrib.auth.backends.ModelBackend'
|
# - 'django.contrib.auth.backends.ModelBackend'
|
||||||
|
|||||||
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1197
-1149
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1230
-1182
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
+1196
-1148
File diff suppressed because it is too large
Load Diff
@@ -2571,10 +2571,17 @@ class PartPricing(models.Model):
|
|||||||
variant_min = None
|
variant_min = None
|
||||||
variant_max = None
|
variant_max = None
|
||||||
|
|
||||||
|
active_only = InvenTreeSetting.get_setting('PRICING_ACTIVE_VARIANTS', False)
|
||||||
|
|
||||||
if self.part.is_template:
|
if self.part.is_template:
|
||||||
variants = self.part.get_descendants(include_self=False)
|
variants = self.part.get_descendants(include_self=False)
|
||||||
|
|
||||||
for v in variants:
|
for v in variants:
|
||||||
|
|
||||||
|
if active_only and not v.active:
|
||||||
|
# Ignore inactive variant parts
|
||||||
|
continue
|
||||||
|
|
||||||
v_min = self.convert(v.pricing.overall_min)
|
v_min = self.convert(v.pricing.overall_min)
|
||||||
v_max = self.convert(v.pricing.overall_max)
|
v_max = self.convert(v.pricing.overall_max)
|
||||||
|
|
||||||
@@ -2605,20 +2612,28 @@ class PartPricing(models.Model):
|
|||||||
self.bom_cost_min,
|
self.bom_cost_min,
|
||||||
self.purchase_cost_min,
|
self.purchase_cost_min,
|
||||||
self.internal_cost_min,
|
self.internal_cost_min,
|
||||||
self.variant_cost_min
|
|
||||||
]
|
]
|
||||||
|
|
||||||
max_costs = [
|
max_costs = [
|
||||||
self.bom_cost_max,
|
self.bom_cost_max,
|
||||||
self.purchase_cost_max,
|
self.purchase_cost_max,
|
||||||
self.internal_cost_max,
|
self.internal_cost_max,
|
||||||
self.variant_cost_max
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if InvenTreeSetting.get_setting('PRICING_USE_SUPPLIER_PRICING', True):
|
purchase_history_override = InvenTreeSetting.get_setting('PRICING_PURCHASE_HISTORY_OVERRIDES_SUPPLIER', False, cache=False)
|
||||||
|
|
||||||
|
if InvenTreeSetting.get_setting('PRICING_USE_SUPPLIER_PRICING', True, cache=False):
|
||||||
|
# Add supplier pricing data, *unless* historical pricing information should override
|
||||||
|
if self.purchase_cost_min is None or not purchase_history_override:
|
||||||
min_costs.append(self.supplier_price_min)
|
min_costs.append(self.supplier_price_min)
|
||||||
|
|
||||||
|
if self.purchase_cost_max is None or not purchase_history_override:
|
||||||
max_costs.append(self.supplier_price_max)
|
max_costs.append(self.supplier_price_max)
|
||||||
|
|
||||||
|
if InvenTreeSetting.get_setting('PRICING_USE_VARIANT_PRICING', True, cache=False):
|
||||||
|
min_costs.append(self.variant_cost_min)
|
||||||
|
max_costs.append(self.variant_cost_max)
|
||||||
|
|
||||||
# Calculate overall minimum cost
|
# Calculate overall minimum cost
|
||||||
for cost in min_costs:
|
for cost in min_costs:
|
||||||
if cost is None:
|
if cost is None:
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
{% include "InvenTree/settings/setting.html" with key="PRICING_DECIMAL_PLACES" %}
|
{% include "InvenTree/settings/setting.html" with key="PRICING_DECIMAL_PLACES" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PRICING_UPDATE_DAYS" icon='fa-calendar-alt' %}
|
{% include "InvenTree/settings/setting.html" with key="PRICING_UPDATE_DAYS" icon='fa-calendar-alt' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PRICING_USE_SUPPLIER_PRICING" icon='fa-check-circle' %}
|
{% include "InvenTree/settings/setting.html" with key="PRICING_USE_SUPPLIER_PRICING" icon='fa-check-circle' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="PRICING_PURCHASE_HISTORY_OVERRIDES_SUPPLIER" icon='fa-shopping-cart' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="PRICING_USE_VARIANT_PRICING" icon='fa-check-circle' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="PRICING_ACTIVE_VARIANTS" %}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -957,10 +957,10 @@ function loadBomTable(table, options={}) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var total = `${top_total}`;
|
var total = `${formatDecimal(top_total)}`;
|
||||||
|
|
||||||
if (top_total != all_total) {
|
if (top_total != all_total) {
|
||||||
total += ` / ${all_total}`;
|
total += ` / ${formatDecimal(all_total)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
|
|||||||
@@ -695,6 +695,11 @@ function loadVariantPricingChart(options={}) {
|
|||||||
|
|
||||||
options.params.ancestor = part;
|
options.params.ancestor = part;
|
||||||
|
|
||||||
|
if (global_settings.PRICING_ACTIVE_VARIANTS) {
|
||||||
|
// Filter variants by "active" status
|
||||||
|
options.params.active = true;
|
||||||
|
}
|
||||||
|
|
||||||
table.inventreeTable({
|
table.inventreeTable({
|
||||||
url: '{% url "api-part-list" %}',
|
url: '{% url "api-part-list" %}',
|
||||||
name: 'variantpricingtable',
|
name: 'variantpricingtable',
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
title: '{% trans "Include sublocations" %}',
|
title: '{% trans "Include sublocations" %}',
|
||||||
description: '{% trans "Include locations" %}',
|
description: '{% trans "Include locations" %}',
|
||||||
},
|
},
|
||||||
|
structural: {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "Structural" %}',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +145,10 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
title: '{% trans "Include subcategories" %}',
|
title: '{% trans "Include subcategories" %}',
|
||||||
description: '{% trans "Include subcategories" %}',
|
description: '{% trans "Include subcategories" %}',
|
||||||
},
|
},
|
||||||
|
structural: {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "Structural" %}',
|
||||||
|
},
|
||||||
starred: {
|
starred: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Subscribed" %}',
|
title: '{% trans "Subscribed" %}',
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ There are several options to deploy InvenTree.
|
|||||||
<div align="center"><h4>
|
<div align="center"><h4>
|
||||||
<a href="https://inventree.readthedocs.io/en/latest/start/docker/">Docker</a>
|
<a href="https://inventree.readthedocs.io/en/latest/start/docker/">Docker</a>
|
||||||
<span> · </span>
|
<span> · </span>
|
||||||
|
<a href="https://marketplace.digitalocean.com/apps/inventree?refcode=d6172576d014"><img src="https://www.deploytodo.com/do-btn-blue-ghost.svg" alt="Deploy to DO" width="auto" height="40" /></a>
|
||||||
|
<span> · </span>
|
||||||
<a href="https://inventree.readthedocs.io/en/latest/start/install/">Bare Metal</a>
|
<a href="https://inventree.readthedocs.io/en/latest/start/install/">Bare Metal</a>
|
||||||
</h4></div>
|
</h4></div>
|
||||||
|
|
||||||
|
|||||||
+23
-3
@@ -55,10 +55,21 @@ root_command() {
|
|||||||
# Check if os and version is supported
|
# Check if os and version is supported
|
||||||
get_distribution
|
get_distribution
|
||||||
echo "### Detected distribution: $OS $VER"
|
echo "### Detected distribution: $OS $VER"
|
||||||
SUPPORTED=true
|
SUPPORTED=true # is thos OS supported?
|
||||||
|
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
|
||||||
|
|
||||||
|
DIST_OS=${OS,,}
|
||||||
|
DIST_VER=$VER
|
||||||
|
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
Ubuntu)
|
Ubuntu)
|
||||||
if [[ $VER != "20.04" ]]; then
|
if [[ $VER == "22.04" ]]; then
|
||||||
|
SUPPORTED=true
|
||||||
|
NEEDS_LIBSSL1_1=true
|
||||||
|
DIST_VER="20.04"
|
||||||
|
elif [[ $VER == "20.04" ]]; then
|
||||||
|
SUPPORTED=true
|
||||||
|
else
|
||||||
SUPPORTED=false
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -93,10 +104,19 @@ root_command() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
|
||||||
|
echo "### Pathching for libssl1.1"
|
||||||
|
|
||||||
|
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
|
||||||
|
do_call "sudo apt-get update"
|
||||||
|
do_call "sudo apt-get install libssl1.1"
|
||||||
|
sudo rm /etc/apt/sources.list.d/focal-security.list
|
||||||
|
fi
|
||||||
|
|
||||||
echo "### Getting and adding key"
|
echo "### Getting and adding key"
|
||||||
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
||||||
echo "### Adding package source"
|
echo "### Adding package source"
|
||||||
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${OS,,}/${VER}.repo"
|
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/$DIST_OS/$DIST_VER.repo"
|
||||||
|
|
||||||
echo "### Updateing package lists"
|
echo "### Updateing package lists"
|
||||||
do_call "sudo apt-get update"
|
do_call "sudo apt-get update"
|
||||||
|
|||||||
@@ -45,10 +45,21 @@ echo "### Installer for InvenTree - source: $publisher/$source_url"
|
|||||||
# Check if os and version is supported
|
# Check if os and version is supported
|
||||||
get_distribution
|
get_distribution
|
||||||
echo "### Detected distribution: $OS $VER"
|
echo "### Detected distribution: $OS $VER"
|
||||||
SUPPORTED=true
|
SUPPORTED=true # is thos OS supported?
|
||||||
|
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
|
||||||
|
|
||||||
|
DIST_OS=${OS,,}
|
||||||
|
DIST_VER=$VER
|
||||||
|
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
Ubuntu)
|
Ubuntu)
|
||||||
if [[ $VER != "20.04" ]]; then
|
if [[ $VER == "22.04" ]]; then
|
||||||
|
SUPPORTED=true
|
||||||
|
NEEDS_LIBSSL1_1=true
|
||||||
|
DIST_VER="20.04"
|
||||||
|
elif [[ $VER == "20.04" ]]; then
|
||||||
|
SUPPORTED=true
|
||||||
|
else
|
||||||
SUPPORTED=false
|
SUPPORTED=false
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -83,10 +94,19 @@ for pkg in $REQS; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
|
||||||
|
echo "### Pathching for libssl1.1"
|
||||||
|
|
||||||
|
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
|
||||||
|
do_call "sudo apt-get update"
|
||||||
|
do_call "sudo apt-get install libssl1.1"
|
||||||
|
sudo rm /etc/apt/sources.list.d/focal-security.list
|
||||||
|
fi
|
||||||
|
|
||||||
echo "### Getting and adding key"
|
echo "### Getting and adding key"
|
||||||
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -
|
||||||
echo "### Adding package source"
|
echo "### Adding package source"
|
||||||
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${OS,,}/${VER}.repo"
|
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/$DIST_OS/$DIST_VER.repo"
|
||||||
|
|
||||||
echo "### Updateing package lists"
|
echo "### Updateing package lists"
|
||||||
do_call "sudo apt-get update"
|
do_call "sudo apt-get update"
|
||||||
|
|||||||
Reference in New Issue
Block a user