mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-18 12:56:31 -06:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b32f081a77 | ||
|
|
f80b116307 | ||
|
|
167784049d | ||
|
|
610c0a8623 | ||
|
|
c2f9bbfdcd | ||
|
|
3df402985a | ||
|
|
35fc954ff8 | ||
|
|
ac83318081 | ||
|
|
acfd39258b | ||
|
|
0287bf78e4 | ||
|
|
f8d6fed06e | ||
|
|
beca269e3a | ||
|
|
506139c1cd | ||
|
|
cdb0f2373c | ||
|
|
287ee8f831 | ||
|
|
b807e47619 | ||
|
|
40e9b33da6 | ||
|
|
72dceb28be | ||
|
|
1a01e8abee | ||
|
|
df0bb34620 | ||
|
|
75a397aab8 | ||
|
|
f4fd84f50f |
18
.github/workflows/docker.yaml
vendored
18
.github/workflows/docker.yaml
vendored
@@ -74,6 +74,14 @@ jobs:
|
||||
python3 ci/version_check.py
|
||||
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
||||
- name: Test Docker Image
|
||||
id: test-docker
|
||||
run: |
|
||||
docker build . --target production --tag inventree-test
|
||||
docker run --rm inventree-test invoke --version
|
||||
docker run --rm inventree-test invoke --list
|
||||
docker run --rm inventree-test gunicorn --version
|
||||
docker run --rm inventree-test pg_dump --version
|
||||
- name: Build Docker Image
|
||||
# Build the development docker image (using docker-compose.yml)
|
||||
run: docker-compose build --no-cache
|
||||
@@ -137,8 +145,8 @@ jobs:
|
||||
inventree/inventree
|
||||
ghcr.io/inventree/inventree
|
||||
|
||||
- name: Build and Push
|
||||
id: build-and-push
|
||||
- name: Push Docker Images
|
||||
id: push-docker
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # pin@v5.0.0
|
||||
with:
|
||||
@@ -152,9 +160,3 @@ jobs:
|
||||
build-args: |
|
||||
commit_hash=${{ env.git_commit_hash }}
|
||||
commit_date=${{ env.git_commit_date }}
|
||||
|
||||
- name: Sign the published image
|
||||
if: ${{ false }} # github.event_name != 'pull_request'
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: cosign sign ${{ steps.meta.outputs.tags }}@${{ steps.build-and-push.outputs.digest }}
|
||||
|
||||
2
.github/workflows/qc_checks.yaml
vendored
2
.github/workflows/qc_checks.yaml
vendored
@@ -505,7 +505,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: cd src/frontend && yarn install
|
||||
- name: Build frontend
|
||||
run: cd src/frontend && npm run build
|
||||
run: cd src/frontend && npm run compile && npm run build
|
||||
- name: Zip frontend
|
||||
run: |
|
||||
cd InvenTree/web/static
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: cd src/frontend && yarn install
|
||||
- name: Build frontend
|
||||
run: cd src/frontend && npm run build
|
||||
run: cd src/frontend && npm run compile && npm run build
|
||||
- name: Zip frontend
|
||||
run: |
|
||||
cd InvenTree/web/static/web
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -23,7 +23,6 @@ ENV PYTHONUNBUFFERED 1
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
|
||||
ENV INVOKE_RUN_SHELL="/bin/ash"
|
||||
|
||||
ENV INVENTREE_LOG_LEVEL="WARNING"
|
||||
ENV INVENTREE_DOCKER="true"
|
||||
|
||||
# InvenTree paths
|
||||
@@ -48,8 +47,6 @@ ENV INVENTREE_BACKGROUND_WORKERS="4"
|
||||
ENV INVENTREE_WEB_ADDR=0.0.0.0
|
||||
ENV INVENTREE_WEB_PORT=8000
|
||||
|
||||
ENV VIRTUAL_ENV=/usr/local
|
||||
|
||||
LABEL org.label-schema.schema-version="1.0" \
|
||||
org.label-schema.build-date=${DATE} \
|
||||
org.label-schema.vendor="inventree" \
|
||||
@@ -65,8 +62,11 @@ RUN apk add --no-cache \
|
||||
libjpeg libwebp zlib \
|
||||
# Weasyprint requirements : https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#alpine-3-12
|
||||
py3-pip py3-pillow py3-cffi py3-brotli pango poppler-utils openldap \
|
||||
# Core database packages
|
||||
postgresql13-client && \
|
||||
# Postgres client
|
||||
postgresql13-client \
|
||||
# MySQL / MariaDB client
|
||||
mariadb-client mariadb-connector-c \
|
||||
&& \
|
||||
# fonts
|
||||
apk --update --upgrade --no-cache add fontconfig ttf-freefont font-noto terminus-font && fc-cache -f
|
||||
|
||||
@@ -96,7 +96,7 @@ FROM inventree_base as prebuild
|
||||
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
RUN ./install_build_packages.sh --no-cache --virtual .build-deps && \
|
||||
pip install --user uv --no-cache-dir && pip install -r base_requirements.txt -r requirements.txt --no-cache && \
|
||||
pip install --user -r base_requirements.txt -r requirements.txt --no-cache && \
|
||||
apk --purge del .build-deps
|
||||
|
||||
# Frontend builder image:
|
||||
|
||||
@@ -84,22 +84,48 @@ class InvenTreeResource(ModelResource):
|
||||
|
||||
return [f for f in fields if f.column_name not in fields_to_exclude]
|
||||
|
||||
def before_import(self, dataset, using_transactions, dry_run, **kwargs):
|
||||
"""Run custom code before importing data.
|
||||
|
||||
- Determine the list of fields which need to be converted to empty strings
|
||||
"""
|
||||
# Construct a map of field names
|
||||
db_fields = {field.name: field for field in self.Meta.model._meta.fields}
|
||||
|
||||
for field_name, field in self.fields.items():
|
||||
# Skip read-only fields (they cannot be imported)
|
||||
if field.readonly:
|
||||
continue
|
||||
|
||||
# Determine the name of the associated column in the dataset
|
||||
column = getattr(field, 'column_name', field_name)
|
||||
|
||||
# Determine the attribute name of the associated database field
|
||||
attribute = getattr(field, 'attribute', field_name)
|
||||
|
||||
# Check if the associated database field is a non-nullable string
|
||||
if db_field := db_fields.get(attribute):
|
||||
if (
|
||||
isinstance(db_field, CharField)
|
||||
and db_field.blank
|
||||
and not db_field.null
|
||||
):
|
||||
if column not in self.CONVERT_NULL_FIELDS:
|
||||
self.CONVERT_NULL_FIELDS.append(column)
|
||||
|
||||
return super().before_import(dataset, using_transactions, dry_run, **kwargs)
|
||||
|
||||
def before_import_row(self, row, row_number=None, **kwargs):
|
||||
"""Run custom code before importing each row.
|
||||
|
||||
- Convert any null fields to empty strings, for fields which do not support null values
|
||||
"""
|
||||
# We can automatically determine which fields might need such a conversion
|
||||
for field in self.Meta.model._meta.fields:
|
||||
if isinstance(field, CharField):
|
||||
if field.blank and not field.null:
|
||||
if field.name not in self.CONVERT_NULL_FIELDS:
|
||||
self.CONVERT_NULL_FIELDS.append(field.name)
|
||||
|
||||
for field in self.CONVERT_NULL_FIELDS:
|
||||
if field in row and row[field] is None:
|
||||
row[field] = ''
|
||||
|
||||
return super().before_import_row(row, row_number, **kwargs)
|
||||
|
||||
|
||||
class CustomRateAdmin(RateAdmin):
|
||||
"""Admin interface for the Rate class."""
|
||||
|
||||
@@ -87,11 +87,24 @@ def generateTestKey(test_name: str) -> str:
|
||||
key = test_name.strip().lower()
|
||||
key = key.replace(' ', '')
|
||||
|
||||
# Remove any characters that cannot be used to represent a variable
|
||||
key = re.sub(r'[^a-zA-Z0-9_]', '', key)
|
||||
def valid_char(char: str):
|
||||
"""Determine if a particular character is valid for use in a test key."""
|
||||
if not char.isprintable():
|
||||
return False
|
||||
|
||||
# If the key starts with a digit, prefix with an underscore
|
||||
if key[0].isdigit():
|
||||
if char.isidentifier():
|
||||
return True
|
||||
|
||||
if char.isalnum():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# Remove any characters that cannot be used to represent a variable
|
||||
key = ''.join([c for c in key if valid_char(c)])
|
||||
|
||||
# If the key starts with a non-identifier character, prefix with an underscore
|
||||
if len(key) > 0 and not key[0].isidentifier():
|
||||
key = '_' + key
|
||||
|
||||
return key
|
||||
|
||||
@@ -352,7 +352,12 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
|
||||
try:
|
||||
instance.full_clean()
|
||||
except (ValidationError, DjangoValidationError) as exc:
|
||||
data = exc.message_dict
|
||||
if hasattr(exc, 'message_dict'):
|
||||
data = exc.message_dict
|
||||
elif hasattr(exc, 'message'):
|
||||
data = {'non_field_errors': [str(exc.message)]}
|
||||
else:
|
||||
data = {'non_field_errors': [str(exc)]}
|
||||
|
||||
# Change '__all__' key (django style) to 'non_field_errors' (DRF style)
|
||||
if '__all__' in data:
|
||||
|
||||
@@ -294,7 +294,10 @@ if LDAP_AUTH:
|
||||
|
||||
# get global options from dict and use ldap.OPT_* as keys and values
|
||||
global_options_dict = get_setting(
|
||||
'INVENTREE_LDAP_GLOBAL_OPTIONS', 'ldap.global_options', {}, dict
|
||||
'INVENTREE_LDAP_GLOBAL_OPTIONS',
|
||||
'ldap.global_options',
|
||||
default_value=None,
|
||||
typecast=dict,
|
||||
)
|
||||
global_options = {}
|
||||
for k, v in global_options_dict.items():
|
||||
@@ -364,7 +367,10 @@ if LDAP_AUTH:
|
||||
)
|
||||
AUTH_LDAP_DENY_GROUP = get_setting('INVENTREE_LDAP_DENY_GROUP', 'ldap.deny_group')
|
||||
AUTH_LDAP_USER_FLAGS_BY_GROUP = get_setting(
|
||||
'INVENTREE_LDAP_USER_FLAGS_BY_GROUP', 'ldap.user_flags_by_group', {}, dict
|
||||
'INVENTREE_LDAP_USER_FLAGS_BY_GROUP',
|
||||
'ldap.user_flags_by_group',
|
||||
default_value=None,
|
||||
typecast=dict,
|
||||
)
|
||||
AUTH_LDAP_FIND_GROUP_PERMS = True
|
||||
|
||||
@@ -482,7 +488,7 @@ Configure the database backend based on the user-specified values.
|
||||
logger.debug('Configuring database backend:')
|
||||
|
||||
# Extract database configuration from the config.yaml file
|
||||
db_config = CONFIG.get('database', {})
|
||||
db_config = CONFIG.get('database', None)
|
||||
|
||||
if not db_config:
|
||||
db_config = {}
|
||||
@@ -558,7 +564,10 @@ Ref: https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-OPTIONS
|
||||
# connecting to the database server (such as a replica failover) don't sit and
|
||||
# wait for possibly an hour or more, just tell the client something went wrong
|
||||
# and let the client retry when they want to.
|
||||
db_options = db_config.get('OPTIONS', db_config.get('options', {}))
|
||||
db_options = db_config.get('OPTIONS', db_config.get('options', None))
|
||||
|
||||
if db_options is None:
|
||||
db_options = {}
|
||||
|
||||
# Specific options for postgres backend
|
||||
if 'postgres' in db_engine: # pragma: no cover
|
||||
@@ -721,7 +730,10 @@ if TRACING_ENABLED: # pragma: no cover
|
||||
logger.info('OpenTelemetry tracing enabled')
|
||||
|
||||
_t_resources = get_setting(
|
||||
'INVENTREE_TRACING_RESOURCES', 'tracing.resources', {}, dict
|
||||
'INVENTREE_TRACING_RESOURCES',
|
||||
'tracing.resources',
|
||||
default_value={},
|
||||
typecast=dict,
|
||||
)
|
||||
cstm_tags = {'inventree.env.' + k: v for k, v in inventree_tags.items()}
|
||||
tracing_resources = {**cstm_tags, **_t_resources}
|
||||
@@ -733,7 +745,12 @@ if TRACING_ENABLED: # pragma: no cover
|
||||
console=get_boolean_setting(
|
||||
'INVENTREE_TRACING_CONSOLE', 'tracing.console', False
|
||||
),
|
||||
auth=get_setting('INVENTREE_TRACING_AUTH', 'tracing.auth', {}),
|
||||
auth=get_setting(
|
||||
'INVENTREE_TRACING_AUTH',
|
||||
'tracing.auth',
|
||||
default_value=None,
|
||||
typecast=dict,
|
||||
),
|
||||
is_http=get_setting('INVENTREE_TRACING_IS_HTTP', 'tracing.is_http', True),
|
||||
append_http=get_boolean_setting(
|
||||
'INVENTREE_TRACING_APPEND_HTTP', 'tracing.append_http', True
|
||||
@@ -1158,7 +1175,9 @@ CUSTOM_SPLASH = get_custom_file(
|
||||
'INVENTREE_CUSTOM_SPLASH', 'customize.splash', 'custom splash'
|
||||
)
|
||||
|
||||
CUSTOMIZE = get_setting('INVENTREE_CUSTOMIZE', 'customize', {})
|
||||
CUSTOMIZE = get_setting(
|
||||
'INVENTREE_CUSTOMIZE', 'customize', default_value=None, typecast=dict
|
||||
)
|
||||
|
||||
# Load settings for the frontend interface
|
||||
FRONTEND_SETTINGS = config.get_frontend_settings(debug=DEBUG)
|
||||
|
||||
@@ -541,7 +541,7 @@ class TestHelpers(TestCase):
|
||||
# TODO: Re-implement this test when we are happier with the external service
|
||||
# dl_helper("https://httpstat.us/200?sleep=5000", requests.exceptions.ReadTimeout, timeout=1)
|
||||
|
||||
large_img = 'https://github.com/inventree/InvenTree/raw/master/InvenTree/InvenTree/static/img/paper_splash_large.jpg'
|
||||
large_img = 'https://github.com/inventree/InvenTree/raw/0.14.x/InvenTree/InvenTree/static/img/paper_splash_large.jpg'
|
||||
|
||||
InvenTreeSetting.set_setting(
|
||||
'INVENTREE_DOWNLOAD_IMAGE_MAX_SIZE', 1, change_user=None
|
||||
|
||||
@@ -19,7 +19,7 @@ from dulwich.repo import NotGitRepository, Repo
|
||||
from .api_version import INVENTREE_API_TEXT, INVENTREE_API_VERSION
|
||||
|
||||
# InvenTree software version
|
||||
INVENTREE_SW_VERSION = '0.14.0 dev'
|
||||
INVENTREE_SW_VERSION = '0.14.5'
|
||||
|
||||
# Discover git
|
||||
try:
|
||||
|
||||
@@ -269,7 +269,7 @@ class FileManagementFormView(MultiStepFormView):
|
||||
for idx, item in row_data.items():
|
||||
column_data = {
|
||||
'name': self.column_names[idx],
|
||||
'guess': self.column_selections[idx],
|
||||
'guess': self.column_selections.get(idx, ''),
|
||||
}
|
||||
|
||||
cell_data = {'cell': item, 'idx': idx, 'column': column_data}
|
||||
|
||||
@@ -379,11 +379,11 @@ class BomItemResource(InvenTreeResource):
|
||||
report_skipped = False
|
||||
clean_model_instances = True
|
||||
|
||||
exclude = ['checksum', 'id', 'part', 'sub_part', 'validated']
|
||||
exclude = ['checksum', 'part', 'sub_part', 'validated']
|
||||
|
||||
level = Field(attribute='level', column_name=_('BOM Level'), readonly=True)
|
||||
|
||||
bom_id = Field(
|
||||
id = Field(
|
||||
attribute='pk', column_name=_('BOM Item ID'), widget=widgets.IntegerWidget()
|
||||
)
|
||||
|
||||
@@ -476,7 +476,6 @@ class BomItemResource(InvenTreeResource):
|
||||
if is_importing:
|
||||
to_remove += [
|
||||
'level',
|
||||
'pk',
|
||||
'part',
|
||||
'part__IPN',
|
||||
'part__name',
|
||||
|
||||
@@ -138,6 +138,8 @@ def update_parameter_values(apps, schema_editor):
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
('part', '0108_auto_20230516_1334'),
|
||||
]
|
||||
|
||||
@@ -3428,6 +3428,13 @@ class PartTestTemplate(InvenTree.models.InvenTreeMetadataModel):
|
||||
|
||||
self.key = helpers.generateTestKey(self.test_name)
|
||||
|
||||
if len(self.key) == 0:
|
||||
raise ValidationError({
|
||||
'test_name': _(
|
||||
'Invalid template name - must include at least one alphanumeric character'
|
||||
)
|
||||
})
|
||||
|
||||
self.validate_unique()
|
||||
super().clean()
|
||||
|
||||
@@ -3445,7 +3452,9 @@ class PartTestTemplate(InvenTree.models.InvenTreeMetadataModel):
|
||||
|
||||
if tests.exists():
|
||||
raise ValidationError({
|
||||
'test_name': _('Test with this name already exists for this part')
|
||||
'test_name': _(
|
||||
'Test template with the same key already exists for part'
|
||||
)
|
||||
})
|
||||
|
||||
super().validate_unique(exclude)
|
||||
|
||||
@@ -431,6 +431,29 @@ class TestTemplateTest(TestCase):
|
||||
|
||||
self.assertEqual(variant.getTestTemplates().count(), n + 1)
|
||||
|
||||
def test_key_generation(self):
|
||||
"""Test the key generation method."""
|
||||
variant = Part.objects.get(pk=10004)
|
||||
|
||||
invalid_names = ['', '+', '+++++++', ' ', '<>$&&&']
|
||||
|
||||
for name in invalid_names:
|
||||
template = PartTestTemplate(part=variant, test_name=name)
|
||||
with self.assertRaises(ValidationError):
|
||||
template.clean()
|
||||
|
||||
valid_names = [
|
||||
'Собранный щит',
|
||||
'!! 123 Собранный щит <><><> $$$$$ !!!',
|
||||
'----hello world----',
|
||||
'Olá Mundo',
|
||||
'我不懂中文',
|
||||
]
|
||||
|
||||
for name in valid_names:
|
||||
template = PartTestTemplate(part=variant, test_name=name)
|
||||
template.clean()
|
||||
|
||||
|
||||
class PartSettingsTest(InvenTreeTestCase):
|
||||
"""Tests to ensure that the user-configurable default values work as expected.
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.apps import AppConfig
|
||||
|
||||
from maintenance_mode.core import set_maintenance_mode
|
||||
|
||||
from InvenTree.ready import canAppAccessDatabase, isInMainThread
|
||||
from InvenTree.ready import canAppAccessDatabase, isInMainThread, isInWorkerThread
|
||||
from plugin import registry
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
@@ -24,7 +24,8 @@ class PluginAppConfig(AppConfig):
|
||||
def ready(self):
|
||||
"""The ready method is extended to initialize plugins."""
|
||||
# skip loading if we run in a background thread
|
||||
if not isInMainThread():
|
||||
|
||||
if not isInMainThread() and not isInWorkerThread():
|
||||
return
|
||||
|
||||
if not canAppAccessDatabase(
|
||||
|
||||
@@ -112,7 +112,7 @@ class ScheduleMixin:
|
||||
@property
|
||||
def has_scheduled_tasks(self):
|
||||
"""Are tasks defined for this plugin."""
|
||||
return bool(self.scheduled_tasks)
|
||||
return bool(self.get_scheduled_tasks())
|
||||
|
||||
def validate_scheduled_tasks(self):
|
||||
"""Check that the provided scheduled tasks are valid."""
|
||||
|
||||
@@ -30,7 +30,7 @@ class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
|
||||
}
|
||||
|
||||
TME_IS_QRCODE_REGEX = re.compile(r'([^\s:]+:[^\s:]+\s+)+(\S+(\s|$)+)+')
|
||||
TME_IS_BARCODE2D_REGEX = re.compile(r'(([^\s]+)(\s+|$))+')
|
||||
TME_IS_OLD_BARCODE2D_REGEX = re.compile(r'(([^\s]+)(\s+|$))+')
|
||||
|
||||
# Custom field mapping
|
||||
TME_QRCODE_FIELDS = {
|
||||
@@ -52,22 +52,19 @@ class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
|
||||
key, value = item.split(':')
|
||||
if key in self.TME_QRCODE_FIELDS:
|
||||
barcode_fields[self.TME_QRCODE_FIELDS[key]] = value
|
||||
|
||||
return barcode_fields
|
||||
|
||||
elif self.TME_IS_BARCODE2D_REGEX.fullmatch(barcode_data):
|
||||
# 2D Barcode format e.g. "PWBP-302 1PMPNWBP-302 Q1 K19361337/1"
|
||||
elif self.TME_IS_OLD_BARCODE2D_REGEX.fullmatch(barcode_data):
|
||||
# Old 2D Barcode format e.g. "PWBP-302 1PMPNWBP-302 Q1 K19361337/1"
|
||||
for item in barcode_data.split(' '):
|
||||
for k, v in self.ecia_field_map().items():
|
||||
if item.startswith(k):
|
||||
barcode_fields[v] = item[len(k) :]
|
||||
else:
|
||||
return {}
|
||||
barcode_fields = self.parse_ecia_barcode2d(barcode_data)
|
||||
|
||||
# Custom handling for order number
|
||||
if SupplierBarcodeMixin.CUSTOMER_ORDER_NUMBER in barcode_fields:
|
||||
order_number = barcode_fields[SupplierBarcodeMixin.CUSTOMER_ORDER_NUMBER]
|
||||
if SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER in barcode_fields:
|
||||
order_number = barcode_fields[SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER]
|
||||
order_number = order_number.split('/')[0]
|
||||
barcode_fields[SupplierBarcodeMixin.CUSTOMER_ORDER_NUMBER] = order_number
|
||||
barcode_fields[SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER] = order_number
|
||||
|
||||
return barcode_fields
|
||||
|
||||
@@ -138,7 +138,13 @@ class MixinBase:
|
||||
if fnc_name is True:
|
||||
return True
|
||||
|
||||
return getattr(self, fnc_name, True)
|
||||
attr = getattr(self, fnc_name, True)
|
||||
|
||||
if callable(attr):
|
||||
return attr()
|
||||
else:
|
||||
return attr
|
||||
|
||||
return False
|
||||
|
||||
def add_mixin(self, key: str, fnc_enabled=True, cls=None):
|
||||
|
||||
@@ -4,7 +4,7 @@ Checklist of steps to perform at each code release
|
||||
|
||||
### Update Version String
|
||||
|
||||
Update `INVENTREE_SW_VERSION` in [version.py](https://github.com/inventree/InvenTree/blob/master/InvenTree/InvenTree/version.py)
|
||||
Update `INVENTREE_SW_VERSION` in [version.py](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/InvenTree/version.py)
|
||||
|
||||
### Increment API Version
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# Note that for postgreslql, we use the 13 version, which matches the version used in the InvenTree docker image
|
||||
|
||||
apk add gcc g++ musl-dev openssl-dev libffi-dev cargo python3-dev openldap-dev \
|
||||
libstdc++ build-base linux-headers py3-grpcio \
|
||||
jpeg-dev openjpeg-dev libwebp-dev zlib-dev \
|
||||
sqlite sqlite-dev \
|
||||
mariadb-connector-c-dev mariadb-client mariadb-dev \
|
||||
|
||||
@@ -96,7 +96,7 @@ The HEAD of the "stable" branch represents the latest stable release code.
|
||||
|
||||
## API versioning
|
||||
|
||||
The [API version](https://github.com/inventree/InvenTree/blob/master/InvenTree/InvenTree/api_version.py) needs to be bumped every time when the API is changed.
|
||||
The [API version](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/InvenTree/api_version.py) needs to be bumped every time when the API is changed.
|
||||
|
||||
## Environment
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ For further information, read more about [installing plugins](./plugins/install.
|
||||
|
||||
### Plugin Base Class
|
||||
|
||||
Custom plugins must inherit from the [InvenTreePlugin class](https://github.com/inventree/InvenTree/blob/2d1776a151721d65d0ae007049d358085b2fcfd5/InvenTree/plugin/plugin.py#L204). Any plugins installed via the methods outlined above will be "discovered" when the InvenTree server launches.
|
||||
Custom plugins must inherit from the [InvenTreePlugin class](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/plugin.py#L204). Any plugins installed via the methods outlined above will be "discovered" when the InvenTree server launches.
|
||||
|
||||
!!! warning "Namechange"
|
||||
The name of the base class was changed with `0.7.0` from `IntegrationPluginBase` to `InvenTreePlugin`. While the old name is still available till `0.8.0` we strongly suggest upgrading your plugins. Deprecation warnings are raised if the old name is used.
|
||||
@@ -28,7 +28,7 @@ Please read all release notes and watch out for warnings - we generally provide
|
||||
|
||||
#### Plugins
|
||||
|
||||
General classes and mechanisms are provided under the `plugin` [namespaces](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/__init__.py). These include:
|
||||
General classes and mechanisms are provided under the `plugin` [namespaces](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/__init__.py). These include:
|
||||
|
||||
```python
|
||||
# Management objects
|
||||
@@ -44,7 +44,7 @@ MixinNotImplementedError # Is raised if a mixin was not implemented (core mec
|
||||
|
||||
#### Mixins
|
||||
|
||||
Mixins are split up internally to keep the source tree clean and enable better testing separation. All public APIs that should be used are exposed under `plugin.mixins`. These include all built-in mixins and notification methods. An up-to-date reference can be found in the source code (current master can be [found here](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/mixins/__init__.py)).
|
||||
Mixins are split up internally to keep the source tree clean and enable better testing separation. All public APIs that should be used are exposed under `plugin.mixins`. These include all built-in mixins and notification methods. An up-to-date reference can be found in the source code (current master can be [found here](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/mixins/__init__.py)).
|
||||
|
||||
#### Models and other internal InvenTree APIs
|
||||
|
||||
@@ -72,7 +72,7 @@ MIN_VERSION = None # Lowest InvenTree version number that is supported by the p
|
||||
MAX_VERSION = None # Highest InvenTree version number that is supported by the plugin
|
||||
```
|
||||
|
||||
Refer to the [sample plugins](https://github.com/inventree/InvenTree/tree/master/InvenTree/plugin/samples) for further examples.
|
||||
Refer to the [sample plugins](https://github.com/inventree/InvenTree/tree/0.14.x/InvenTree/plugin/samples) for further examples.
|
||||
|
||||
### Plugin Config
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ If a locate plugin is installed and activated, the [InvenTree mobile app](../../
|
||||
|
||||
### Implementation
|
||||
|
||||
Refer to the [InvenTree source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/samples/locate/locate_sample.py) for a simple implementation example.
|
||||
Refer to the [InvenTree source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/samples/locate/locate_sample.py) for a simple implementation example.
|
||||
|
||||
@@ -16,7 +16,7 @@ Additionally the `add_label_context` method, allowing custom context data to be
|
||||
|
||||
### Example
|
||||
|
||||
A sample plugin which provides additional context data to the report templates can be found [in the InvenTree source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/samples/integration/report_plugin_sample.py):
|
||||
A sample plugin which provides additional context data to the report templates can be found [in the InvenTree source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/samples/integration/report_plugin_sample.py):
|
||||
|
||||
```python
|
||||
"""Sample plugin for extending reporting functionality"""
|
||||
|
||||
@@ -59,4 +59,4 @@ class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin):
|
||||
```
|
||||
|
||||
!!! info "More Info"
|
||||
For more information on any of the methods described below, refer to the InvenTree source code. [A working example is available as a starting point](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/samples/integration/scheduled_task.py).
|
||||
For more information on any of the methods described below, refer to the InvenTree source code. [A working example is available as a starting point](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/samples/integration/scheduled_task.py).
|
||||
|
||||
@@ -65,7 +65,7 @@ Additionally, add the following imports after the extended line.
|
||||
#### Blocks
|
||||
The page_base file is split into multiple sections called blocks. This allows you to implement sections of the webpage while getting many items like navbars, sidebars, and general layout provided for you.
|
||||
|
||||
The current default page base can be found [here](https://github.com/inventree/InvenTree/blob/master/InvenTree/templates/page_base.html). Look through this file to determine overridable blocks. The [stock app](https://github.com/inventree/InvenTree/tree/master/InvenTree/stock) offers a great example of implementing these blocks.
|
||||
The current default page base can be found [here](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/templates/page_base.html). Look through this file to determine overridable blocks. The [stock app](https://github.com/inventree/InvenTree/tree/0.14.x/InvenTree/stock) offers a great example of implementing these blocks.
|
||||
|
||||
!!! warning "Sidebar Block"
|
||||
You may notice that implementing the `sidebar` block doesn't initially work. Be sure to enable the sidebar using JavaScript. This can be achieved by appending the following code, replacing `label` with a label of your choosing, to the end of your template file.
|
||||
|
||||
@@ -9,7 +9,7 @@ The `ValidationMixin` class enables plugins to perform custom validation of obje
|
||||
Any of the methods described below can be implemented in a custom plugin to provide functionality as required.
|
||||
|
||||
!!! info "More Info"
|
||||
For more information on any of the methods described below, refer to the InvenTree source code. [A working example is available as a starting point](https://github.com/inventree/InvenTree/blob/master/InvenTree/plugin/samples/integration/validation_sample.py).
|
||||
For more information on any of the methods described below, refer to the InvenTree source code. [A working example is available as a starting point](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/plugin/samples/integration/validation_sample.py).
|
||||
|
||||
!!! info "Multi Plugin Support"
|
||||
It is possible to have multiple plugins loaded simultaneously which support validation methods. For example when validating a field, if one plugin returns a null value (`None`) then the *next* plugin (if available) will be queried.
|
||||
|
||||
@@ -183,4 +183,4 @@ Finally added a `{% raw %}|floatformat:0{% endraw %}` to the quantity that remov
|
||||
|
||||
A default *BOM Report* template is provided out of the box, which is useful for generating simple test reports. Furthermore, it may be used as a starting point for developing custom BOM reports:
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_bill_of_materials_report.html) for the default test report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_bill_of_materials_report.html) for the default test report template.
|
||||
|
||||
@@ -321,4 +321,4 @@ This will result a report page like this:
|
||||
|
||||
A default *Build Report* template is provided out of the box, which is useful for generating simple test reports. Furthermore, it may be used as a starting point for developing custom BOM reports:
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_build_order_base.html) for the default build report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_build_order_base.html) for the default build report template.
|
||||
|
||||
@@ -12,7 +12,7 @@ Some common functions are provided for use in custom report and label templates.
|
||||
```
|
||||
|
||||
!!! tip "Use the Source, Luke"
|
||||
To see the full range of available helper functions, refer to the source file [report.py](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templatetags/report.py) where these functions are defined!
|
||||
To see the full range of available helper functions, refer to the source file [report.py](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templatetags/report.py) where these functions are defined!
|
||||
|
||||
## Assigning Variables
|
||||
|
||||
|
||||
@@ -62,4 +62,4 @@ Price: {% render_currency line.total_line_price %}
|
||||
|
||||
A default *Purchase Order Report* template is provided out of the box, which is useful for generating simple test reports. Furthermore, it may be used as a starting point for developing custom BOM reports:
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_po_report_base.html) for the default purchase order report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_po_report_base.html) for the default purchase order report template.
|
||||
|
||||
@@ -155,7 +155,7 @@ InvenTree supports the following reporting functionality:
|
||||
InvenTree is supplied with a number of default templates "out of the box". These are generally quite simple, but serve as a starting point for building custom reports to suit a specific need.
|
||||
|
||||
!!! tip "Read the Source"
|
||||
The source code for the default reports is [available on GitHub](https://github.com/inventree/InvenTree/tree/master/InvenTree/report/templates/report). Use this as a guide for generating your own reports!
|
||||
The source code for the default reports is [available on GitHub](https://github.com/inventree/InvenTree/tree/0.14.x/InvenTree/report/templates/report). Use this as a guide for generating your own reports!
|
||||
|
||||
## Creating Reports
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ In addition to the default report context variables, the following context varia
|
||||
|
||||
A default report template is provided out of the box, which can be used as a starting point for developing custom return order report templates.
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_return_order_report_base.html) for the default return order report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_return_order_report_base.html) for the default return order report template.
|
||||
|
||||
@@ -28,4 +28,4 @@ In addition to the default report context variables, the following variables are
|
||||
|
||||
A default *Sales Order Report* template is provided out of the box, which is useful for generating simple test reports. Furthermore, it may be used as a starting point for developing custom BOM reports:
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_so_report_base.html) for the default sales order report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_so_report_base.html) for the default sales order report template.
|
||||
|
||||
@@ -13,4 +13,4 @@ You can use all content variables from the [StockLocation](./context_variables.m
|
||||
|
||||
A default report template is provided out of the box, which can be used as a starting point for developing custom return order report templates.
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_slr_report.html) for the default stock location report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_slr_report.html) for the default stock location report template.
|
||||
|
||||
@@ -84,4 +84,4 @@ A default *Test Report* template is provided out of the box, which is useful for
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/master/InvenTree/report/templates/report/inventree_test_report_base.html) for the default test report template.
|
||||
View the [source code](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/report/templates/report/inventree_test_report_base.html) for the default test report template.
|
||||
|
||||
@@ -22,7 +22,7 @@ The InvenTree server tries to locate the `config.yaml` configuration file on sta
|
||||
!!! tip "Config File Location"
|
||||
When the InvenTree server boots, it will report the location where it expects to find the configuration file
|
||||
|
||||
The configuration file *template* can be found on [GitHub](https://github.com/inventree/InvenTree/blob/master/InvenTree/config_template.yaml)
|
||||
The configuration file *template* can be found on [GitHub](https://github.com/inventree/InvenTree/blob/0.14.x/InvenTree/config_template.yaml)
|
||||
|
||||
!!! info "Template File"
|
||||
The default configuration file (as defined by the template linked above) will be copied to the specified configuration file location on first run, if a configuration file is not found in that location.
|
||||
@@ -56,7 +56,6 @@ The following basic options are available:
|
||||
| INVENTREE_ADMIN_ENABLED | admin_enabled | Enable the [django administrator interface]({% include "django.html" %}/ref/contrib/admin/) | True |
|
||||
| INVENTREE_ADMIN_URL | admin_url | URL for accessing [admin interface](../settings/admin.md) | admin |
|
||||
| INVENTREE_LANGUAGE | language | Default language | en-us |
|
||||
| INVENTREE_BASE_URL | base_url | Server base URL | *Not specified* |
|
||||
| INVENTREE_AUTO_UPDATE | auto_update | Database migrations will be run automatically | False |
|
||||
|
||||
## Server Access
|
||||
|
||||
@@ -27,13 +27,13 @@ The following guide provides a streamlined production InvenTree installation, wi
|
||||
|
||||
### Required Files
|
||||
|
||||
The following files required for this setup are provided with the InvenTree source, located in the `./docker/` directory of the [InvenTree source code](https://github.com/inventree/InvenTree/tree/master/docker/production):
|
||||
The following files required for this setup are provided with the InvenTree source, located in the `./docker/` directory of the [InvenTree source code](https://github.com/inventree/InvenTree/tree/0.14.x/docker/):
|
||||
|
||||
| Filename | Description |
|
||||
| --- | --- |
|
||||
| [docker-compose.yml](https://github.com/inventree/InvenTree/blob/master/docker/docker-compose.yml) | The docker compose script |
|
||||
| [.env](https://github.com/inventree/InvenTree/blob/master/docker/.env) | Environment variables |
|
||||
| [Caddyfile](https://github.com/inventree/InvenTree/blob/master/docker/Caddyfile) | Caddy configuration file |
|
||||
| [docker-compose.yml](https://raw.githubusercontent.com/inventree/InvenTree/0.14.x/docker/docker-compose.yml) | The docker compose script |
|
||||
| [.env](https://raw.githubusercontent.com/inventree/InvenTree/0.14.x/docker/.env)| Environment variables |
|
||||
| [Caddyfile](https://raw.githubusercontent.com/inventree/InvenTree/0.14.x/docker/Caddyfile) | Caddy configuration file |
|
||||
|
||||
Download these files to a directory on your local machine.
|
||||
|
||||
@@ -109,6 +109,9 @@ This command launches the following containers:
|
||||
!!! success "Up and Running!"
|
||||
You should now be able to view the InvenTree login screen at [http://inventree.localhost](http://inventree.localhost) (or whatever custom domain you have configured in the `.env` file).
|
||||
|
||||
!!! tip "External Access"
|
||||
Note that `http://inventree.localhost` will only be available from the machine you are running the code on. To make it accessible externally, change `INVENTREE_SITE_URL` to a host address which can be accessed by other computers on your network.
|
||||
|
||||
## Updating InvenTree
|
||||
|
||||
To update your InvenTree installation to the latest version, follow these steps:
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
},
|
||||
{
|
||||
"pattern": "http://127.0.0.1"
|
||||
},
|
||||
{
|
||||
"pattern": "https://twitter.com"
|
||||
},
|
||||
{
|
||||
"pattern": "https://www.reddit.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ cryptography==42.0.4
|
||||
# via pdfminer-six
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
django==4.2.10
|
||||
django==4.2.11
|
||||
# via django-slowtests
|
||||
django-slowtests==1.1.1
|
||||
django-test-migrations==1.3.0
|
||||
@@ -57,7 +57,7 @@ pyyaml==6.0.1
|
||||
# via pre-commit
|
||||
requests==2.31.0
|
||||
# via coveralls
|
||||
setuptools==69.1.0
|
||||
setuptools==69.2.0
|
||||
# via
|
||||
# nodeenv
|
||||
# pip-tools
|
||||
|
||||
@@ -45,7 +45,7 @@ python-barcode[images] # Barcode generator
|
||||
python-dotenv # Environment variable management
|
||||
pyyaml>=6.0.1 # YAML parsing
|
||||
qrcode[pil] # QR code generator
|
||||
rapidfuzz # Fuzzy string matching
|
||||
rapidfuzz # Fuzzy string matching
|
||||
regex # Advanced regular expressions
|
||||
sentry-sdk # Error reporting (optional)
|
||||
setuptools # Standard dependency
|
||||
@@ -53,6 +53,7 @@ tablib[xls,xlsx,yaml] # Support for XLS and XLSX formats
|
||||
weasyprint # PDF generation
|
||||
|
||||
# OpenTelemetry dependencies
|
||||
grpcio==1.54.2 # Pinned to ensure docker image builds correctly
|
||||
opentelemetry-api
|
||||
opentelemetry-sdk
|
||||
opentelemetry-exporter-otlp
|
||||
|
||||
@@ -52,7 +52,7 @@ deprecated==1.2.14
|
||||
diff-match-patch==20230430
|
||||
# via django-import-export
|
||||
dj-rest-auth==5.0.2
|
||||
django==4.2.10
|
||||
django==4.2.11
|
||||
# via
|
||||
# dj-rest-auth
|
||||
# django-allauth
|
||||
@@ -137,7 +137,7 @@ googleapis-common-protos==1.62.0
|
||||
# via
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
grpcio==1.60.1
|
||||
grpcio==1.54.2
|
||||
# via opentelemetry-exporter-otlp-proto-grpc
|
||||
gunicorn==21.2.0
|
||||
html5lib==1.1
|
||||
@@ -296,7 +296,7 @@ rpds-py==0.17.1
|
||||
# referencing
|
||||
sentry-sdk==1.40.0
|
||||
# via django-q-sentry
|
||||
setuptools==69.1.0
|
||||
setuptools==69.2.0
|
||||
# via
|
||||
# django-money
|
||||
# opentelemetry-instrumentation
|
||||
|
||||
Reference in New Issue
Block a user