mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-15 19:45:46 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
4
.github/workflows/docker.yaml
vendored
4
.github/workflows/docker.yaml
vendored
@ -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'
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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>
|
||||||
|
|
||||||
|
@ -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